能,但必须用增量修正而非全量计算;mysql中需用after insert/delete/update触发器配合on duplicate key update或双路update,并确保汇总字段非null且有唯一索引,避免select into或跨表查询引发错误或性能问题。

触发器里不能用 SELECT ... INTO 临时表
很多刚写触发器的人会想:先查出明细数据,再算总和,最后更新汇总表。但 MySQL 的 BEFORE INSERT 或 AFTER INSERT 触发器里不支持 SELECT ... INTO 语句(报错 ERROR 1327: Undeclared variable),也不能直接在触发器里声明游标处理多行——除非你用存储过程套一层,但那就偏离“自动更新”的初衷了。
真正可行的做法是:只针对当前操作的那条记录做增量修正。比如插入一笔订单,就给对应客户的 total_amount 加上这笔的 amount;删除时则减去。
-
AFTER INSERT触发器中,用NEW.amount和NEW.customer_id定位并更新汇总表 -
AFTER DELETE触发器中,用OLD.amount和OLD.customer_id做反向更新 -
AFTER UPDATE要拆成两步:先减掉旧值OLD.amount,再加回新值NEW.amount - 务必加
WHERE customer_id = NEW.customer_id条件,否则会误更新其他客户
UPDATE 汇总表时必须处理 NULL 值
如果客户第一次下单,汇总表里还没有该 customer_id 对应的记录,UPDATE 语句不会生效,也不会报错——结果就是汇总值“消失”了。这时候得靠 INSERT ... ON DUPLICATE KEY UPDATE 或 INSERT IGNORE + 单独 UPDATE 组合来兜底。
更稳妥的是用 INSERT ... ON DUPLICATE KEY UPDATE,前提是汇总表的 customer_id 是主键或唯一索引:
INSERT INTO customer_summary (customer_id, total_amount) VALUES (NEW.customer_id, NEW.amount) ON DUPLICATE KEY UPDATE total_amount = total_amount + NEW.amount;
注意:ON DUPLICATE KEY UPDATE 中的 total_amount = total_amount + NEW.amount 在首次插入时会把 NULL + value 算成 NULL,所以汇总表字段必须设默认值 DEFAULT 0,且不能允许 NULL。
触发器对批量 INSERT/DELETE 性能影响很大
MySQL 触发器是按行执行的。如果你执行 INSERT INTO orders VALUES (...), (...), (...) 插入 1000 行,触发器就会运行 1000 次——每次都要单独查、更新或插入汇总表,I/O 和锁开销陡增。
- 线上高并发场景下,建议避开触发器,改用应用层事务后异步更新,或定时任务跑
SUM()全量重算 - 如果非要用触发器,至少确保汇总表有
PRIMARY KEY (customer_id),避免全表扫描 - 不要在触发器里调用自定义函数或访问其他大表,容易引发死锁或超时
- 测试时用
SHOW PROFILES查看触发器实际耗时,别只看 SQL 执行时间
PostgreSQL 的触发器写法完全不同
PostgreSQL 不支持 MySQL 那种简写的 NEW.column,必须显式声明触发器函数,且函数返回类型必须是 TRIGGER。最常踩的坑是忘了在函数末尾写 RETURN NEW 或 RETURN OLD,导致触发器静默失败。
一个最小可用的 PostgreSQL 触发器函数示例:
CREATE OR REPLACE FUNCTION update_customer_total()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO customer_summary (customer_id, total_amount)
VALUES (NEW.customer_id, NEW.amount)
ON CONFLICT (customer_id) DO UPDATE
SET total_amount = customer_summary.total_amount + EXCLUDED.amount;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
注意:EXCLUDED 是 PostgreSQL 特有的关键字,代表本次冲突的“新值”,不能写成 NEW —— 否则在 ON CONFLICT 分支里会报错。
真正麻烦的不是语法,而是触发器无法感知事务是否最终提交。万一主表插入成功但汇总表更新失败,又没加重试或补偿逻辑,数据就永久不一致了。











