本节摘要:视图是基于查询的"虚拟表",不实际存数据(物化视图除外)。本节讲视图的作用、创建使用、和物化视图的区别。
阅读完本节,你应当能够:
视图(VIEW)是一条 SELECT 语句的命名结果,表现为一张虚拟表。查视图时,DBMS 执行底层 SELECT 返回结果,视图本身不存数据(除非物化视图)。
CREATE VIEW 北京客户 AS SELECT CustomerID, FirstName, LastName FROM Customers WHERE City = '北京';
之后可以像查表一样查视图:
SELECT * FROM 北京客户 WHERE FirstName = 'Alice';

视图三大用途:
-- 创建 CREATE VIEW 客户订单汇总 AS SELECT c.CustomerID, c.FirstName, COUNT(o.OrderID) AS 订单数, SUM(o.Amount) AS 总额 FROM Customers c LEFT JOIN Orders o ON c.CustomerID = o.CustomerID GROUP BY c.CustomerID, c.FirstName; -- 使用 SELECT * FROM 客户订单汇总 WHERE 订单数 > 5; -- 修改定义 CREATE OR REPLACE VIEW 客户订单汇总 AS SELECT ...; -- 或 ALTER VIEW 客户订单汇总 AS SELECT ...; -- 删除 DROP VIEW 客户订单汇总;
简单视图(单表、无聚合、无 DISTINCT)可以直接 INSERT/UPDATE/DELETE,操作会作用到底层表。复杂视图(多表 JOIN、聚合)通常不可更新。
-- 简单视图可更新 CREATE VIEW 北京客户 AS SELECT * FROM Customers WHERE City = '北京'; INSERT INTO 北京客户 VALUES (104, 'Dan', '北京'); -- 插入底层 Customers 表
普通视图是虚拟的,不存数据。物化视图(Materialized View)把查询结果实际存下来,查询快(直接读存的结果),但要定期刷新保持最新。
| 维度 | 普通视图 | 物化视图 |
|---|---|---|
| 存数据 | 不存 | 存 |
| 查询速度 | = 底层查询 | 快(读存的结果) |
| 实时性 | 实时 | 取决于刷新频率 |
| 维护 | 无 | 要刷新 |
物化视图适合"查询重、对实时性要求不高"的场景,如报表。不是所有 DBMS 都直接支持物化视图(MySQL 没有,PostgreSQL/Oracle 有),没有的可以用"表 + 定时任务刷新"模拟。
⚠️ 常见坑:以为视图能加速查询——普通视图不存数据,性能等于底层查询。要加速得靠索引或物化视图。
💡 关键直觉:视图是"存查询不存数据"的虚拟表,用于简化查询、控制权限、稳定接口。普通视图不加速,加速靠索引或物化视图。
下一节讲索引——真正能加速查询的利器。
Q1:视图能加速查询吗?
普通视图不能。它只是保存了查询语句,执行时仍然要跑底层查询,性能与直接写那段 SQL 相同。真正能加速的是:1) 底层表加索引;2) 物化视图(预计算结果)。视图的价值在"封装逻辑"和"权限隔离",不在性能。
Q2:视图能更新数据吗?
简单视图(单表、不含聚合、不含 DISTINCT、WHERE 不涉及计算列)可以 INSERT/UPDATE/DELETE,操作会作用到底层表。复杂视图(JOIN、聚合、子查询)通常不可更新。MySQL 里用 WITH CHECK OPTION 可限制插入行必须满足视图条件。
Q3:视图和临时表有什么区别?
视图是"语句别名",不占数据空间;临时表会真实落数据(会话内有效)。视图适合反复使用的查询逻辑;临时表适合复杂中间结果先落盘再多次处理。需要"存储中间结果"时用临时表,需要"统一查询接口"时用视图。
Q4:视图嵌套视图可以吗?
可以,但不建议过深(超过 2-3 层)。嵌套视图可读性差、性能可能受影响(优化器要展开多层)。尽量一层视图直接基于表。
Q5:视图上的权限怎么控制?
可以只授予视图权限而不授予底层表权限:用户能查视图、看不到底层表的敏感列。这是"最小权限"的经典落地:对外暴露"客户视图"(无身份证号),不暴露"客户表"。生产环境报表类需求常用这招。