ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Node系列 · 数据库:视图

Node系列 · 数据库:视图 Node系列 · 数据库视图视图View是虚拟表——查询时按定义动态生成结果不存储实际数据。视图能简化复杂 JOIN、控制数据访问权限、抽象业务规则——但性能与可维护性有 trade-off需要明确何时该用、何时该拆。一、什么是视图视图是包装好的 SELECT 语句对外表现像一张表-- 创建一个视图学生 班级 综合成绩 CREATE VIEW v_student_score AS SELECT s.id AS student_id, s.name AS student_name, s.class_id AS class_id, c.name AS class_name, sc.subject, sc.score FROM student s JOIN class c ON c.id s.class_id JOIN score sc ON sc.student_id s.id;之后可以像查表一样查视图SELECT*FROMv_student_scoreWHEREclass_name高三一班;::: info视图不存储数据。每次查视图MySQL 都会执行它背后的 SELECT 语句。数据始终在原表里。:::二、视图的核心作用2.1 简化复杂查询把多表 JOIN、聚合、过滤封装成视图业务代码直接SELECT * FROM v_xxx-- 没有视图每次都要写完整 JOIN SELECT s.name, SUM(sc.score) AS total FROM student s JOIN score sc ON sc.student_id s.id WHERE s.class_id 3 GROUP BY s.id; -- 有视图业务代码只关心简单查询 SELECT student_name, SUM(score) AS total FROM v_student_score WHERE class_id 3 GROUP BY student_id;2.2 数据权限隔离让不同角色看到不同字段-- 给运营看的视图脱敏手机号 CREATE VIEW v_student_for_ops AS SELECT s.id, s.name, s.class_id, CONCAT(LEFT(s.phone, 3), ****, RIGHT(s.phone, 4)) AS phone_masked FROM student s; -- 运营账号只有 v_student_for_ops 的权限看不到真实手机号2.3 抽象业务规则“近 30 天活跃用户” 这种业务口径经常变。封装成视图调用方不感知CREATE VIEW v_active_users_30d AS SELECT DISTINCT user_id FROM login_log WHERE created_at DATE_SUB(NOW(), INTERVAL 30 DAY);三、创建与管理视图3.1 创建CREATEVIEWv_xxxASSELECT...;3.2 替换已有视图CREATEORREPLACEVIEWv_xxxASSELECT...;3.3 删除DROPVIEWIFEXISTSv_xxx;3.4 查看视图定义SHOWCREATEVIEWv_xxx;四、视图的限制4.1 视图不一定能更新视图背后是 SELECT有些视图是只读的不能INSERT/UPDATE/DELETE视图定义是否可更新单表、无聚合、无 DISTINCT、无 GROUP BY✅ 可更新多表 JOIN❌ 不可更新含聚合函数COUNT/SUM❌ 不可更新含DISTINCT/GROUP BY/HAVING❌ 不可更新含UNION❌ 不可更新子查询引用FROM的表❌ 不可更新::: warningMySQL 允许看似可更新的视图背后静默失败——比如INSERT INTO v_xxx没报错但实际没生效。生产环境对视图的写操作要谨慎最好绕过视图直接改原表。:::4.2 视图性能不一定好每次查视图都执行一次底层 SELECT。如果视图背后 JOIN 了 5 张表又没建索引比直接写 JOIN 更慢。EXPLAINSELECT*FROMv_student_scoreWHEREclass_name高三一班;-- typeALL rows100 万 → 全表扫描性能差优化方法给底层表的关键字段建索引视图里加WHERE条件过滤用物化视图MySQL 不支持但可以定时 INSERT INTO 一张真实表4.3 视图嵌套有上限MySQL 视图嵌套层数有上限默认不高复杂业务不要套太多层。五、视图 vs 临时表 vs 子查询维度视图临时表子查询存储不存储虚拟存储在内存 / 磁盘不存储复用多查询可复用会话内复用单查询内索引不能加索引能加索引不能适用稳定抽象层复杂中间计算一次性查询-- 视图稳定抽象全局可复用 CREATE VIEW v_top_students AS SELECT student_id, AVG(score) AS avg_score FROM score GROUP BY student_id HAVING avg_score 90; -- 临时表会话内的中间结果可建索引 CREATE TEMPORARY TABLE tmp_score AS SELECT student_id, AVG(score) AS avg_score FROM score GROUP BY student_id; ALTER TABLE tmp_score ADD INDEX idx_avg (avg_score); -- 子查询一次性 SELECT * FROM ( SELECT student_id, AVG(score) AS avg_score FROM score GROUP BY student_id ) t WHERE avg_score 90;六、Node 端使用视图视图对应用层是透明的——当表用const mysql require(mysql2/promise); // 视图对 Node 来说就是一张普通表 const [rows] await pool.execute( SELECT * FROM v_student_score WHERE class_id ? ORDER BY score DESC LIMIT 10, [3] );七、何时用视图✅适合用复杂 JOIN 的复用不同业务都要查同一份数据权限隔离不同角色看不同字段业务口径封装活跃用户等❌不适合性能关键的查询视图不能加索引复杂视图性能差频繁变更的业务逻辑改视图定义比改应用代码麻烦多层嵌套层数多难调试八、小结视图 包装好的 SELECT对外是虚拟表不存储数据三大作用简化查询 / 权限隔离 / 抽象业务规则多表 JOIN、聚合、DISTINCT 视图不能更新视图性能 底层 SELECT 性能复杂视图要靠索引优化与临时表 / 子查询的取舍视图是稳定抽象层临时表是会话中间计算子查询是一次性
返回列表