视图
视图(View)是把一条 SELECT 语句存成"虚拟表"——它本身不存数据,查询时动态执行底层 SQL。视图是 SQL 复用查询逻辑、控制权限、抽象表结构变化的利器,在真实项目里非常常用。
1. CREATE VIEW 创建视图
视图本质上就是"命名的 SELECT"。创建后,你可以像查普通表一样查它:
-- 视图(View):把一条 SELECT 语句存成"虚拟表"
-- 视图本身【不存数据】,只在查询时动态执行底层 SQL
-- 基础语法
CREATE VIEW view_name AS
SELECT ...;
-- 示例:创建一个"成年学生"视图
CREATE VIEW adult_students AS
SELECT id, name, age, email
FROM students
WHERE age >= 18;
-- 用法和普通表一样
SELECT * FROM adult_students;
SELECT name, age FROM adult_students WHERE age > 20;
-- 视图可以再被其他视图引用(但层数多了会变慢)
CREATE VIEW adult_active AS
SELECT * FROM adult_students WHERE status = 'active';关键认知:视图不存数据,每次查询都重新执行底层 SELECT。这意味着视图永远反映最新的底层数据——但也意味着大表上的复杂视图每次查询都很慢。
2. 删除与修改视图
视图的 DDL 操作很安全——删视图不影响底层数据:
-- 删除视图(不影响底层数据)
DROP VIEW adult_students;
DROP VIEW IF EXISTS adult_students; -- 推荐加 IF EXISTS
-- 修改视图(用 CREATE OR REPLACE 替换,MySQL / PostgreSQL)
CREATE OR REPLACE VIEW adult_students AS
SELECT id, name, age, email, city
FROM students
WHERE age >= 18;
-- MySQL 也有 ALTER VIEW 语法
ALTER VIEW adult_students AS
SELECT id, name FROM students WHERE age >= 18;
-- 查看视图定义(MySQL)
SHOW CREATE VIEW adult_students;实际项目里推荐用 CREATE OR REPLACE,一条语句搞定创建+修改,不用先 DROP 再 CREATE(避免短暂时间内视图不存在导致业务报错)。
3. 视图的三大用途
视图不是"装饰品",它在真实项目里有明确的应用场景:
-- 视图的核心用途
-- 1. 简化复杂查询(最常见的用途)
-- 团队里常用的"用户订单汇总"查询很复杂,封装成视图
CREATE VIEW user_order_summary AS
SELECT
u.id,
u.name,
COUNT(o.id) AS order_count,
COALESCE(SUM(o.amount), 0) AS total_spent,
MAX(o.created_at) AS last_order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;
-- 业务方查起来就像查普通表一样简单
SELECT * FROM user_order_summary WHERE total_spent > 1000;
-- 2. 权限控制(只暴露部分列)
GRANT SELECT ON adult_students TO 'public_user';
-- public_user 只能看到成年学生,看不到未成年人
-- 3. 抽象底层表结构变化
-- 表拆分 / 重命名时,只要视图逻辑不变,应用层 SQL 不用改三大用途速记:(1) 简化复杂查询(把 50 行 SQL 包成一个视图,业务方查起来像查普通表);(2) 权限控制(只暴露部分列给某些用户);(3) 抽象底层表结构变化(表重命名/拆分时,只要视图逻辑不变,应用层 SQL 不用改)。
4. 可更新视图
部分视图可以执行 INSERT / UPDATE / DELETE,操作会反映到底层表。规则是:视图必须直接对应单张表的行(不能含聚合 / JOIN / DISTINCT):
-- 可更新视图(Updatable View)
-- 某些视图可以执行 INSERT / UPDATE / DELETE,会反映到底层表
-- 规则:视图必须【直接对应】单张表的行,不能有聚合/JOIN/ DISTINCT
CREATE VIEW active_students AS
SELECT id, name, age FROM students WHERE status = 'active';
-- 这种视图可以更新(直接映射单表)
INSERT INTO active_students (id, name, age) VALUES (10, '小明', 20);
-- 等价于 INSERT INTO students ...(status 会被设为默认值)
UPDATE active_students SET age = 21 WHERE id = 10;
-- 等价于 UPDATE students SET age = 21 WHERE id = 10
-- ⚠️ 含聚合 / JOIN / DISTINCT / GROUP BY 的视图【不可更新】
CREATE VIEW student_stats AS
SELECT class_id, COUNT(*) AS cnt FROM students GROUP BY class_id;
UPDATE student_stats SET cnt = 30 WHERE class_id = 1; -- ❌ 报错
-- 数据库无法把"改 cnt"映射到底层表
-- WITH CHECK OPTION:防止插入不符合视图 WHERE 的数据
CREATE VIEW adult_students AS
SELECT * FROM students WHERE age >= 18
WITH CHECK OPTION;
-- INSERT age=15 会报错(不符合视图条件)含聚合 / JOIN 的视图不可更新——因为数据库无法把"修改一个 COUNT(*)"映射到底层表。WITH CHECK OPTION 防止通过视图插入不符合 WHERE 条件的行。
5. 物化视图(Materialized View)
普通视图每次查询都重算,大表上很慢。物化视图是另一种存在——它真正存储数据,查询时直接读取,性能极高:
-- 物化视图(Materialized View)
-- 和普通视图不同,物化视图【真正存储数据】
-- 适合不经常变化、查询频繁的统计场景
-- PostgreSQL 原生支持
CREATE MATERIALIZED VIEW daily_sales AS
SELECT
DATE(created_at) AS day,
SUM(amount) AS total
FROM orders
GROUP BY DATE(created_at);
-- 查询时直接读物化数据,不用重算(秒级)
SELECT * FROM daily_sales WHERE day = '2024-08-05';
-- 缺点:数据不会自动更新,需要手动刷新
REFRESH MATERIALIZED VIEW daily_sales;
-- MySQL 不直接支持物化视图,常见替代方案:
-- 1. 创建实体的"汇总表",用定时任务(CRON / Event)刷新
CREATE TABLE daily_sales_cache (
day DATE PRIMARY KEY,
total DECIMAL(10,2)
);
-- 每晚跑:
INSERT INTO daily_sales_cache
SELECT DATE(created_at), SUM(amount) FROM orders
WHERE DATE(created_at) = CURDATE() - INTERVAL 1 DAY
ON DUPLICATE KEY UPDATE total = VALUES(total);
-- 2. 用触发器实时维护(写入多则慎用,影响写性能)物化视图的代价是数据不实时——需要手动 REFRESH,或定时任务刷新。它适合"统计结果变化慢、查询频繁"的场景(日报、周报、排行榜)。MySQL 不直接支持,常见替代是建实体汇总表 + 定时任务维护。
6. 视图 vs 表:什么时候用哪个?
选视图还是选表,看需求性质:
-- 视图 vs 表:什么时候用哪个?
-- 用【表】的场景:
-- 1. 存储真实业务数据
-- 2. 需要建索引优化查询
-- 3. 高频写入(INSERT / UPDATE)
-- 4. 数据量大且查询复杂
-- 用【视图】的场景:
-- 1. 简化团队常用的复杂查询
-- 2. 给不同角色暴露不同列(权限)
-- 3. 底层表结构变化时保护应用层
-- 4. 报表查询(配合物化视图或缓存表)
-- ⚠️ 视图的性能陷阱
-- 1. 视图是"语法糖",每次查询都重算
-- 2. 嵌套视图(视图套视图)可能极慢,优化困难
-- 3. 大表上的聚合视图,每次查都全表扫描
-- 这种情况改用【物化视图】或【汇总表】一个经验法则:能用视图就用视图(零数据冗余、永远最新),但性能不够时改用物化视图或汇总表。两者配合使用是日常。
视图的优缺点总结
- 优点:简化复杂查询、逻辑复用、权限隔离、表结构变化时保护应用层。
- 缺点:每次查询都重算(性能可能差)、嵌套视图难优化、调试困难(报错信息可能指向底层表)。
- 最佳实践:视图层数 ≤ 2、避免在大表上做聚合视图、性能关键场景用物化视图。
恭喜,SQL 系列完结!
这是 SQL 系列 12 篇的最后一篇。回过头看,你已经走完了完整的学习路径:
- 基础:简介 → SELECT 语法 → DDL 建表 → DML 增删改
- 查询:WHERE 排序 → JOIN 多表 → GROUP BY 分组
- 进阶:子查询 → SQL 函数
- 工程化:索引 → 事务 → 视图
掌握了这些,你已经能独立设计数据库表结构、写出复杂的多表统计查询、用索引优化慢查询、用事务保证数据一致性。SQL 是为数不多"学了能用一辈子"的技能,核心概念四十多年几乎没变——无论编程语言怎么迭代,你的 SQL 能力都会持续增值。
下一步建议:多刷题(LeetCode Database、SQLZOO)、读源码(看公司内部的复杂 SQL)、实战优化(找慢查询用 EXPLAIN 分析)。SQL 是肌肉记忆,光看不写学不会。祝你在数据世界里探索愉快!
← 上一篇 事务
返回 SQL 教程目录