视图
约 775 字大约 3 分钟
布欧-Lewyon
2026-05-15
首页 › MySQL › 高级特性(在新窗口打开) › 视图
视图(View)是一个虚拟表,其内容由 SELECT 查询定义。视图不存储数据,只是一个命名查询,每次查询视图时都会执行其定义。
为什么使用视图
-- 没有视图:重复写复杂查询
SELECT d.name, COUNT(e.id) AS emp_count, AVG(e.salary) AS avg_sal
FROM employee e
JOIN department d ON e.dept_id = d.id
GROUP BY d.name;
-- 创建视图后:像查表一样使用
CREATE VIEW dept_stats AS
SELECT d.id, d.name, COUNT(e.id) AS emp_count, AVG(e.salary) AS avg_sal
FROM employee e
JOIN department d ON e.dept_id = d.id
GROUP BY d.name;
SELECT * FROM dept_stats WHERE emp_count > 2;适用场景:
- 封装复杂查询(多表 JOIN、聚合),简化访问
- 提供行/列级安全(让某些用户只能看到视图定义的部分数据)
- 向后兼容(重构表结构后,通过视图保持旧 API)
创建与使用
-- 基本语法
CREATE [OR REPLACE] VIEW view_name AS
select_statement;
-- 创建视图
CREATE VIEW high_salary AS
SELECT id, name, dept_id, salary
FROM employee
WHERE salary >= 15000;
-- 使用视图
SELECT * FROM high_salary; -- 就像查普通表WITH CHECK OPTION
当通过视图执行 INSERT / UPDATE 时,保证操作后的行仍然满足视图的 WHERE 条件:
CREATE VIEW young_employee AS
SELECT id, name, age, dept_id
FROM employee
WHERE age < 30
WITH CHECK OPTION;
-- 可以通过视图插入 25 岁的员工
INSERT INTO young_employee (id, name, age, dept_id)
VALUES (100, '新员工', 25, 1);
-- 会报错:35 岁不满足 age < 30
INSERT INTO young_employee (id, name, age, dept_id)
VALUES (101, '老员工', 35, 1);
-- ERROR: CHECK OPTION failed可更新视图的条件
并非所有视图都支持 INSERT / UPDATE / DELETE。可更新视图必须满足:
- SELECT 中不使用聚合函数(
SUM/COUNT等) - 不使用
DISTINCT、GROUP BY、HAVING、UNION、UNION ALL - 不使用子查询(在 FROM 或 SELECT 列中)
- 不使用窗口函数
-- ✅ 可更新
CREATE VIEW simple_employee AS
SELECT id, name, age, dept_id FROM employee;
-- ❌ 不可更新(包含聚合函数)
CREATE VIEW dept_avg_salary AS
SELECT dept_id, AVG(salary) AS avg_sal FROM employee GROUP BY dept_id;视图与性能
MySQL 有两种视图处理算法:
| 算法 | 行为 | 场景 |
|---|---|---|
MERGE | 将视图查询合并到外部查询 | 简单视图,性能好 |
TEMPTABLE | 将视图结果物化成临时表再处理 | 复杂视图(GROUP BY、子查询等) |
-- 查看视图使用的算法
EXPLAIN SELECT * FROM dept_stats;
-- 如果显示 "Using temporary" 说明使用了 TEMPTABLE 算法视图不是性能优化手段——
MERGE算法等效于直接写子查询,TEMPTABLE算法反而更慢。视图主要服务于代码复用和安全控制。
管理视图
-- 查看视图定义
SHOW CREATE VIEW dept_stats;
-- 修改视图
ALTER VIEW dept_stats AS
SELECT d.id, d.name, COUNT(e.id) AS emp_count
FROM employee e
JOIN department d ON e.dept_id = d.id
GROUP BY d.id;
-- 删除视图
DROP VIEW IF EXISTS dept_stats;小结
- 视图是命名查询,不存数据,每次查询时执行定义。
- 通过
WITH CHECK OPTION防止视图外的 DML 操作。 - 只有简单的 SELECT(无聚合、GROUP BY、DISTINCT 等)视图才可更新。
- 视图的主要价值在代码复用和安全控制,而非性能优化。
