0 ~> 前置概念辨析
0.1 两个 “视图” 的本质区分
明确强调二者无任何关联,更加精准的定义如下:
- 本文的视图(view):数据库模式层面的对象,是一段被命名存储的 select 查询定义,以虚拟表的形式对外提供访问能力,属于 sql 标准语法范畴。
- 事务中的 read view:innodb 引擎 mvcc 机制的底层组件,是事务执行快照读时生成的可见性判断快照,用于判定当前事务能看到哪些版本的行数据,属于事务隔离级别的内部实现逻辑。
二者分属完全不同的技术维度,没有任何关联。
1 ~> 视图基础概念
1.1 核心定义
视图是一个虚拟表,其内容由查询定义,同真实表一样包含命名的列和行数据。
1.1.1 易错问题
如下所示:
- “在内存级别上创建好了一张表”“把筛选出来的数据插入到表中”“查询结果变成了一个临时表结构”
- 视图本身不存储任何数据,也不会默认生成内存临时表。视图的本质是一段被持久化存储的 select 查询语句。当查询视图时,mysql 会将视图定义与外层查询合并后执行,所有数据均实时从基表计算得到。
- 补充执行算法:
merge合并算法(默认优先):将视图定义的 sql 与外层查询 sql 合并为单条语句执行,无额外临时表开销,性能等价于直接执行原生查询。temptable临时表算法:当视图定义包含聚合、分组、distinct 等无法合并的逻辑时,mysql 先将视图查询结果写入临时表(内存或磁盘),再基于临时表执行外层查询,存在额外性能开销。
- “视图本质上就是一种表结构”
- 视图是虚拟表,仅存储定义元数据(mysql 5.x 存
.frm结构文件,8.0 后纳入数据字典),没有对应的.ibd数据文件,不持久化存储行数据,与物理基表有本质区别。删除视图后无对应数据文件,也印证了这一点。
- 视图是虚拟表,仅存储定义元数据(mysql 5.x 存
1.2 基表与视图的联动关系
这个表述对吗:视图的数据变化会影响基表,基表的数据变化也会影响视图。
1.2.1 纠正
实际上该结论存在前提缺失,完整严谨的表述为:
- 基表变更 → 视图同步变更:恒成立。视图数据是查询时实时计算生成,基表数据变更后,再次查询视图必然反映最新数据。
- 视图变更 → 基表同步变更:仅可更新视图支持,且存在严格的语法约束。绝大多数复杂视图(聚合、多表深度连接等)无法执行写入操作。
2 ~> 视图基本操作
2.1 创建视图
2.1.1 标准语法
create view视图名as select语句;存在空格缺失问题,标准语法如下:
create [or replace] view 视图名 [(自定义列名列表)] as select 查询语句 [with [cascaded | local] check option];
关键字说明:
or replace:视图已存在时直接覆盖原有定义,避免重名报错。自定义列名列表:可重命名视图的输出列,数量必须与 select 结果列数一致;不指定则默认沿用 select 的列名。with check option:写入视图数据时校验数据是否满足视图的 where 过滤条件,防止写入后数据从视图中 “消失”。
2.1.2 示例
基于 emp、dept 表创建员工姓名 - 部门名称视图。
-- 创建内连接视图 create view v_ename_dname as select emp.ename, dept.dname from emp inner join dept on emp.deptno = dept.deptno;
2.2 查询视图
视图的查询语法与普通物理表完全一致,支持 where、order by、联表等所有查询语法。
-- 查询视图并按部门排序 select * from v_ename_dname order by dname;
执行逻辑等价于直接运行视图定义的完整 select 语句。
2.3 视图数据修改
2.3.1 通过视图修改基表
示例:更新视图中的员工姓名,基表同步变更。
-- 通过视图更新员工姓名 update v_ename_dname set ename = 'smith' where ename = 'smith';
- 执行结果:视图与基表
emp的ename字段同步更新。 - 成立前提:
ename列唯一来自单表emp,且视图满足可更新条件;若尝试更新dname(来自dept表),多表连接视图通常不支持跨表更新。
2.3.2 修改基表同步到视图
示例:更新基表部门名称,视图数据同步变更。
-- 修改基表 dept 的部门名称 update dept set dname = 'aaaaa' where deptno = 30;
- 执行结果:再次查询视图,所有 30 号部门对应的
dname同步更新。 - 结论:基表数据变更必然实时反映到视图中,无任何前提条件。
2.3.3 可更新视图的核心约束
补充工业界标准约束。
视图支持 update/insert/delete 必须同时满足:
- 无聚合函数(sum/count/max 等)、无 group by、无 distinct、无 union、无 having。
- 视图列不能是表达式、常量或函数计算的结果。
- 单表视图天然支持更新;多表连接视图仅允许更新其中一张基表的列,且连接不能导致行映射歧义。
- from 子句中不能包含子查询。
2.4 删除视图
2.4.1 标准语法
drop view [if exists] 视图名;
2.4.2 示例
drop view v_ename_dname;
- 执行后仅删除视图的定义元数据,不会对基表数据产生任何影响。
- 物理层面:删除视图不会删除任何
.ibd数据文件,仅移除对应的视图定义文件。
3 ~> 视图规则与使用限制
- 命名唯一性:同一数据库内,视图名不能与表名、其他视图名重复。
- 创建数量无上限:但复杂查询定义的视图会增加优化器解析成本,可能导致执行计划退化,不建议滥用。
- 功能限制:普通视图无法创建索引,无法关联触发器,不能为列设置默认值。
- 注:mysql 原生不支持物化视图,无法为视图持久化存储数据与索引;若需物化视图需通过定时任务生成物理表手动模拟。
- 权限规则:访问视图需要拥有视图的对应权限,同时视图创建者必须拥有基表的查询权限。视图可实现列级权限控制,只向用户开放允许查看的字段。
- 排序覆盖规则:视图定义中可以写 order by,但如果查询视图的外层语句也包含 order by,视图内部的排序会被外层覆盖,最终以外层排序为准。
- 联表兼容性:视图可与普通物理表混合使用,支持内连接、外连接、子查询等所有表级查询语法。
4 ~> 工程实践与行业现状
4.1 视图的核心价值
判断一下,下面这句话的表述有没有问题:“高频访问不用做多表查询、字段更清晰”。
这句话是有问题的,下面纠正一下:
- sql 复用与简化:将复杂多表关联封装为视图,业务层直接调用,避免重复编写冗余 sql,降低维护成本。
- 逻辑解耦:基表结构变更时,可通过修改视图定义屏蔽底层变化,上层业务代码无需改造。
- 数据安全:实现行列级权限隔离,例如只开放员工姓名、部门字段,隐藏薪资、身份证等敏感数据。
- 性能误区修正:视图不会提升查询性能。merge 算法下性能与原生 sql 完全等价;temptable 算法下反而会增加临时表开销,性能下降。原始笔记中 “方便快速读取” 指的是编写便捷,而非执行性能提升。
4.2 大厂使用规范
互联网行业普遍现状,大厂内部限制使用视图,核心原因如下:
- 运维成本高:业务逻辑下沉到数据库层,增加了 sql 排查、优化的复杂度,不利于 dba 统一管控。
- 架构扩展性差:分库分表、读写分离的分布式架构下,视图基本无法正常使用。
- 研发规范约束:主流研发规范要求业务逻辑全部收敛在应用代码层,数据库仅负责数据存储,避免数据库逻辑过重导致整体架构僵化。
- 学习建议:视图是 sql 标准核心概念,必须掌握其原理与语法;生产环境需谨慎评估,优先在业务代码层封装查询逻辑。
5 ~> 实战例题
5.1 题目
针对 actor 表创建视图 actor_name_view,只包含 first_name 以及 last_name 两列。
5.2 标准解答
create view actor_name_view as select first_name, last_name from actor;
到此这篇关于mysql学习的一大重点之视图(实战例题)的文章就介绍到这了,更多相关mysql视图内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论