6.2 康复处方:存储过程、触发器与视图


6.2 康复处方:存储过程、触发器与视图

本节摘要:存储过程把逻辑放进数据库,触发器在事件上挂钩子,视图给查询起别名。三者的共性是"用对了减负,用错了埋雷"。本节各给一个可用示例与明确的适用边界。

视图:最值得常备的一个

CREATE VIEW v_active_order AS SELECT o.order_id, o.user_id, u.user_name, o.amount, o.status FROM clinic_order o JOIN clinic_user u ON u.user_id = o.user_id WHERE o.status IN (1, 2); SELECT * FROM v_active_order WHERE user_id = 1001;

视图是存起来的查询,不存数据。给报表人员开放一张脱敏视图,比逐条授权列权限省事得多。注意视图嵌套层数多了排查会变难,一层为佳。

存储过程:批处理场景还有位置

DELIMITER // CREATE PROCEDURE purge_expired(IN p_days INT) BEGIN REPEAT DELETE FROM visit_log WHERE visit_at < NOW() - INTERVAL p_days DAY LIMIT 5000; UNTIL ROW_COUNT() = 0 END REPEAT; END // DELIMITER ;

这个分批清理模板能避免大事务。但存储过程的调试、版本管理、迁移成本都高,业务逻辑放应用层几乎总是更好的选择,留下的位置只有批处理运维与极简单的数据整理。

触发器:能不碰就不碰

CREATE TRIGGER trg_order_audit AFTER UPDATE ON clinic_order FOR EACH ROW INSERT INTO order_audit(order_id, old_status, new_status, changed_at) VALUES (OLD.order_id, OLD.status, NEW.status, NOW());

触发器的问题在于"隐性执行":后人看到表结构猜不到有个钩子在偷偷写审计表,性能问题与死锁常常追到这里才发现元凶。审计、同步这类场景有更好工具(binlog、CDC),新项目里我基本不再用触发器。

图:三件套的决策路线

💡 关键直觉:数据库最擅长的是存取与一致性,不是业务编排。凡是需要在数据库里写流程控制的时刻,先问一句这段逻辑放到应用层是不是更好维护。

视图的进阶两式

普通视图外还有两式值得会。第一式是给视图加算法提示,明确它是合并执行还是建临时表:MERGE 把视图定义拼进外部查询,性能与手写等价;TEMPTABLE 先把视图结果物化成临时表,外部条件过滤不了视图内部,扫描量可能放大。聚合视图多走 TEMPTABLE,列表页给聚合视图再加 WHERE 时要留心:

CREATE ALGORITHM = TEMPTABLE VIEW v_user_order_stat AS SELECT user_id, COUNT(*) AS order_cnt, SUM(amount) AS total_amt FROM clinic_order GROUP BY user_id; -- 外部的 user_id 条件无法下推进视图,先全量物化再过滤 SELECT * FROM v_user_order_stat WHERE user_id = 1001;

第二式是可更新视图,视图基于单表、不含聚合时可以直接对视图 INSERT/UPDATE,常用来做"带默认过滤的入口表",比如给运营暴露一个天然排除测试数据的视图。两式的共同提醒:视图是命名复杂的查询,不是性能工具,把它当性能工具用迟早会在执行计划里现形。

存储过程的管理账

存量系统里的存储过程要接手时,先盘家底:

-- 这个库有哪些过程、谁建的、何时改的 SELECT routine_name, created, last_altered, routine_comment FROM information_schema.routines WHERE routine_schema = 'clinic'; -- 查看过程定义(迁移时导出用) SHOW CREATE PROCEDURE purge_expired\G

接手存量过程的处置顺序:先补注释与调用方清单(搜遍代码库与定时任务),再补测试(构造边界数据验证行为),最后再谈改造或下线。最忌讳的是"看不懂但没人调用就删了"——半年后某个季度任务跑出错误报表,才发现调用藏在数据库事件调度器里。

触发器的最后阵地

触发器在现代架构里节节败退,但仍有两块阵地它守得住。一是必须与写入强同步且不能遗漏的簿记,比如某些合规要求的所有变更留痕,触发器比应用代码更难被绕过(直连数据库手工改数据也会被记录)。二是极端写性能敏感场景下省一次应用与数据库的往返。即便如此,用触发器的团队要立两条规:每条触发器必须在表注释与文档里登记;触发器逻辑保持单行、无外部依赖。守住这两条,触发器才不会从器械变成暗器。

一个视图的真实事故档案

收一个真实感十足的档案。某系统有一张三层嵌套的视图,最内层聚合全表,最外层按用户过滤,跑了几个月没人注意。数据涨到三千万行后,一个列表页突然劣化到十秒。拍片发现外层的 user_id 条件无法穿透两层嵌套下推,每次页面请求都在物化三千万行的聚合中间结果。结案手术:把外层条件合并进最内层定义,重写成单层视图,十秒回到两百毫秒。

-- 病灶形态:外层条件推不进去 CREATE VIEW v_inner AS SELECT user_id, SUM(amount) amt FROM clinic_order GROUP BY user_id; CREATE VIEW v_outer AS SELECT * FROM v_inner WHERE user_id > 0; -- 条件在这里失效

档案的教训只有一条:视图嵌套是要还的债。每多一层嵌套,条件与优化器的自由度就少一分,超过一层就该警惕,超过两层就该重构。

本节要点回顾

  • 视图:脱敏与查询封装,放心常用
  • 存储过程:只留批处理运维场景
  • 触发器:隐性执行是排查黑洞,新项目尽量绕开

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U