mysql数据库视图笔记:创建、修改、删除与适用场景

视图一行数据都不存,我为什么还敢把核心报表全压在它上面?

有段三表连接加聚合的统计 SQL,被我抄进了十几个报表和定时任务;底表字段一改名,全局搜索改了一下午,还是漏挂了两个生产报表。

这篇把视图(View)的创建、修改、删除、可更新判定一次讲透,看完你能把重复 SQL 收敛到一处,也能避开我踩过的四个坑。

一、场景:同一段 SQL 抄了十几遍,改一处漏一片

报表要展示员工、部门、城市,还要带部门平均工资,原始写法是一段三表连接加窗口函数,每个用到它的服务都得抄一遍。

sql 复制代码
SELECT e.employee_id,
       e.last_name,
       d.department_name,
       l.city,
       AVG(e.salary) OVER (PARTITION BY e.department_id) AS dept_avg_salary
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;

这段 SQL 出现在报表服务、定时任务、导出接口里。连接逻辑一改,十几处都得同步;更麻烦的是,每个开发抄的版本还略有出入,统计口径慢慢就对不上了。

问题就变成:同一段查询逻辑,能不能只写一份、处处复用?

二、踩坑:视图上线后,四个坑轮流找上门

我把它封成视图,确实省事,可新坑在一周内就凑齐了。

坑 现象 触发时机
底表改列,视图失效 查询视图直接报列不存在,Oracle 中视图变 INVALID 基础表 DROP / RENAME 列,视图仍引用旧列
视图写不进去 报目标表不可更新、非键保留表 视图含多表连接或聚合,却执行 UPDATE / INSERT
改完视图权限丢了 业务账号突然查不了视图 用 DROP 再 CREATE 的方式改视图,授权未重建
视图套视图,性能崩 简单查询嵌套四五层,执行计划巨大 上层视图再建视图,优化器无法合并

这四个坑我都在生产环境背过。底表改列是结构问题,视图写不进去是定义问题,授权丢失是运维习惯问题,嵌套视图是性能问题;它们的根因都指向同一件事------视图到底是个什么对象?

三、底层原理:数据库里根本没有这张"表"

视图(View)是存储在数据字典(Data Dictionary)里的一条 SELECT 语句,对外呈现为虚拟表(Virtual Table)。普通视图不保存任何数据行,只保存定义本身。

查询视图时,数据库执行视图合并(View Merging):把视图定义中的 SELECT 与外层查询拼接改写,再基于基础表(Base Table)生成执行计划。整个过程对调用方透明,你以为在查一张表,引擎查的还是底表,三者的行为差别由此而来。

对比项 基础表 视图 子查询
是否存数据 存,占物理空间 不存,只存定义 不存
生命周期 持久 持久,可反复引用 只在当前语句内
能否独立授权 能 能 不能
结构变更影响 涉及数据迁移 依赖底表,可能失效 改完即走

注意:查视图,就是临时执行一段被保存的 SELECT;物理空间里没有这张表,只有这句话。

四、解决方案:建、改、删、授权一次做对

4.1 创建视图

标准语法如下,方括号为可选项。

sql 复制代码
CREATE VIEW view_name [(column_name [, ...])]
AS
SELECT_statement
[WITH CHECK OPTION];

把开头那段查询收敛成视图,连接逻辑从此只有一份。

sql 复制代码
CREATE VIEW emp_location_info AS
SELECT e.employee_id,
       e.last_name,
       d.department_name,
       l.city
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;

之后所有报表都查同一处,还可以直接追加条件。

sql 复制代码
SELECT * FROM emp_location_info WHERE city = 'Seattle';

需要固定列名、屏蔽底层列名变化时,显式写出列清单。

sql 复制代码
CREATE VIEW emp_location_info_v2 (emp_id, emp_name, dept_name, city) AS
SELECT e.employee_id, e.last_name, d.department_name, l.city
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;

聚合统计也能封装,部门薪资汇总只需维护一次。

sql 复制代码
CREATE VIEW dept_salary_summary AS
SELECT department_id,
       COUNT(*) AS emp_count,
       AVG(salary) AS avg_salary,
       MAX(salary) AS max_salary
FROM employees
GROUP BY department_id;

4.2 修改视图:只替换定义,别裸 DROP

改视图有三种路径,权限结果完全不同。

方式 适用数据库 授权是否保留
CREATE OR REPLACE VIEW MySQL、Oracle 保留
ALTER VIEW SQL Server、MySQL 保留
DROP + CREATE 通用 丢失,需重新授权

MySQL、Oracle 用替换写法。

sql 复制代码
CREATE OR REPLACE VIEW emp_location_info AS
SELECT e.employee_id,
       e.last_name,
       d.department_name,
       l.city,
       l.state_province
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN locations l ON d.location_id = l.location_id;

SQL Server 用 ALTER 写法。

sql 复制代码
ALTER VIEW emp_location_info AS
SELECT ... ;

替换只改定义,视图对象本身没被删除,GRANT 出去的权限还在;DROP 再 CREATE 属于新建对象,旧授权不会跟着回来。

4.3 删除视图

sql 复制代码
DROP VIEW view_name;

视图可能不存在、不想让脚本报错时,用 IF EXISTS。

sql 复制代码
DROP VIEW IF EXISTS view_name;

删视图只删定义,基础表的数据一行不动;但其他视图、存储过程若引用了它,会变成失效状态,需要重新编译或修复。

4.4 用视图做行列权限隔离

employees 表含工资等敏感列。给外部账号只开放编号、姓名、部门三列,先建视图。

sql 复制代码
CREATE VIEW emp_public_info AS
SELECT employee_id, last_name, department_id
FROM employees;

只授权视图,不授权基础表。

sql 复制代码
GRANT SELECT ON emp_public_info TO user_a;

限制行同理,只允许看到 10 号部门的数据。

sql 复制代码
CREATE VIEW emp_dept10 AS
SELECT employee_id, last_name, salary, department_id
FROM employees
WHERE department_id = 10;

4.5 可更新视图与 WITH CHECK OPTION

视图支持 INSERT、UPDATE、DELETE,要同时满足下列条件。

条件 要求
数据来源 仅基于单个基础表
禁止结构 无 GROUP BY、HAVING、聚合函数、DISTINCT、UNION
列要求 无计算列,包含主键或唯一键用于定位行

带 WHERE 条件的可更新视图,加上检查选项(WITH CHECK OPTION),可以防止写入后数据"逃出"视图范围。

sql 复制代码
CREATE VIEW v_dept10_check AS
SELECT employee_id, last_name, salary, department_id
FROM employees
WHERE department_id = 10
WITH CHECK OPTION;

注意:改视图只换定义,DROP 再 CREATE 会把授权一起带走;改视图的默认动作是替换,不是重建。

五、实操验证:判定、拦截、依赖三个动作

5.1 先判定视图能不能写

拿到一个陌生视图,按下面的顺序过一遍定义。

latex 复制代码
┌────────────────────────────────────┐
│ 检查视图定义                        │
└──────────────┬─────────────────────┘
               ▼
┌──────────────────────────────────────┐
│ 是否命中以下任一项?                  │
│  · 多表 JOIN / 子查询                │
│  · GROUP BY / 聚合函数 / HAVING      │
│  · DISTINCT / UNION                  │
│  · 计算列 / 伪列                     │
└──────────────┬───────────────────────┘
               │
       ┌───────┴────────┐
       ▼ 命中任一项      ▼ 全部没有,且含主键/唯一键
┌───────────────┐  ┌──────────────┐
│ 只读,不可更新 │  │ 可更新视图    │
└───────────────┘  └──────────────┘

5.2 验证 CHECK OPTION 的拦截

视图内部调整工资,部门没变,正常执行。

sql 复制代码
UPDATE v_dept10_check
SET salary = 12000
WHERE employee_id = 200;
latex 复制代码
Query OK, 1 row affected

更新后仍满足 department_id = 10,语句放行。

尝试把部门改成 20。

sql 复制代码
UPDATE v_dept10_check
SET department_id = 20
WHERE employee_id = 200;
latex 复制代码
ERROR 1369 (HY000): CHECK OPTION failed 'hr.v_dept10_check'

更新后该行不再属于视图,被 WITH CHECK OPTION 拦截,数据未变更。

5.3 动底表前先查依赖

基础表改列前,先确认哪些视图引用了它,各库查询入口如下。

数据库 依赖/定义查询对象
Oracle USER_DEPENDENCIES、ALL_DEPENDENCIES
SQL Server sys.sql_expression_dependencies
MySQL information_schema.VIEWS
PostgreSQL pg_depend、information_schema.view_table_usage

MySQL 下直接查视图定义。

sql 复制代码
SELECT table_name, view_definition
FROM information_schema.views
WHERE table_schema = 'hr';

变更窗口里先跑一遍依赖查询,再决定改列还是先替换视图,能省掉一次视图失效告警。

注意:视图能不能写,定义说了算;写不进去先查 SELECT 结构,别硬怼。

六、总结延伸:什么时候该用,什么时候别碰

场景 建议
多表连接、聚合统计反复出现 用视图封装,统一口径
敏感列、敏感行需要隔离 用视图 + 只授视图权限
表结构变更、旧系统兼容 用视图维持原接口
高频复杂查询、性能敏感 普通视图无效,考虑物化视图
视图上再套多层视图 别这么干,合并难度和性能都会失控

普通视图不存数据,每次查询动态展开;物化视图(Materialized View)会把结果集真实存下来,用刷新换性能,是数据仓库里的主力。

注意:视图是权限边界,不是安全边界;是逻辑封装,不是性能优化。

参考链接

术语速查表

术语 英文 解释
视图 View 存储在数据字典中的 SELECT 定义,虚拟表
基础表 Base Table 真实存放数据的表,视图的数据来源
数据字典 Data Dictionary 存储数据库对象定义的系统表集合
视图合并 View Merging 查询视图时将视图定义与外层 SQL 拼接改写
检查选项 WITH CHECK OPTION 限制通过视图写入后数据必须仍满足视图条件
物化视图 Materialized View 实际存储查询结果的视图,以刷新换性能
行级安全 Row Level Security 按行控制数据可见性的数据库安全策略
相关推荐
Seraphina3641 分钟前
DVWA(SQL Injection-High,XSS Reflected-Medium,XSS Stored-Medium)
数据库·经验分享·sql·网络安全·xss
@Mike@42 分钟前
12-数据库学习笔记(五种连接算法)
数据库·笔记·学习
韩明君43 分钟前
alacrity学习笔记
笔记·学习
Omics Pro1 小时前
之江实验室NAR|虚拟细胞3阶段训练范式
数据库·人工智能·算法·机器学习·自然语言处理
龙亘川1 小时前
探索智慧文化服务:建设初衷、整体架构、技术支撑、发展现状与实践影响
大数据·数据库·架构
风早爽太1 小时前
Python 学习笔记:数据库迁移工具 ‌Alembic
数据库·python·fastapi·alembic
坤坤子吖1 小时前
Python基础语法学习:函数
开发语言·笔记·python·学习
91刘仁德1 小时前
HTTPS 加密原理与 CA 数字证书:从对称加密到完整通信流程
网络·笔记·网络协议·http·https
java1234_小锋1 小时前
【技术专题】Mysql8 数据库 - Mysql8 数据库基本操作
数据库·mysql