能不用就别用触发器做聚合统计,除非业务写入频次低、事务链路短且不依赖强一致性实时展示;否则易拖慢写入、引发死锁、难以调试,应优先移至应用层或定时任务。

触发器该不该用在聚合统计场景
直接说结论:能不用就别用,除非你确认业务写入频次低、事务链路短、且不依赖强一致性实时展示。MySQL 触发器在 AFTER INSERT/UPDATE/DELETE 中更新聚合表,看似自动,实则容易拖慢主表写入、引发死锁、且难以调试。真正稳定的方案是把聚合逻辑移到应用层或定时任务里——但如果你已在线上用了触发器,又必须快速修复数据一致性问题,那得先理清怎么写才不至于崩。
INSERT 和 DELETE 触发器必须配对写
只写 INSERT 触发器而漏掉 DELETE,聚合值会越积越多;只写 DELETE 而没处理 UPDATE,字段改了但总和不动。常见错误是以为 UPDATE 可以靠 DELETE + INSERT 模拟,但触发器里不能直接删自己刚更新的行,会报 Can't update table 'xxx' in stored function/trigger because it is already used by statement which invoked this stored function/trigger。
-
INSERT触发器:累加新记录的amount到聚合表summary.total -
DELETE触发器:减去被删记录的amount -
UPDATE触发器:用OLD.amount和NEW.amount算差值,再更新summary.total
聚合表字段要带唯一约束防重复更新
如果触发器更新的是无主键/无唯一索引的聚合表,多次执行可能插入重复行,或者 UPDATE ... WHERE 匹配多行导致总和错乱。必须确保聚合表有明确分组键(比如 category_id),且该字段上有 UNIQUE 或 PRIMARY KEY 约束。
例如:
CREATE TABLE summary ( category_id INT PRIMARY KEY, total DECIMAL(12,2) DEFAULT 0 );否则
INSERT INTO summary VALUES (1, 100) ON DUPLICATE KEY UPDATE total = total + 100 就会失效。
触发器里别调用函数或查其他表
一旦触发器里出现 SELECT 查询、自定义函数、或跨库操作,性能会断崖式下跌,且 MySQL 5.7+ 对触发器内非确定性操作限制更严。更危险的是:如果触发器里查的表正好也在被当前事务修改,就会触发 Lock wait timeout exceeded。
正确做法是只做最简原子操作:
UPDATE summary SET total = total + NEW.amount WHERE category_id = NEW.category_id;所有计算逻辑(比如按时间范围过滤、排除状态为 deleted 的记录)必须前置到业务 SQL 里完成,触发器只负责“加/减/差”这一步。
真正在生产环境跑通的关键,不是语法有没有错,而是你能否在每次 INSERT/UPDATE/DELETE 后,用 SELECT 立刻验证聚合值和手动 SUM() 结果一致——不验证,等于没写。











