结论不能直接、安全、可维护地用触发器实现多维报表的实时预聚合,因其在事务内同步执行易拖慢主dml、引发死锁;应优先选用物化视图、定时增量任务或cdc异步方案。

触发器能用来做实时预聚合吗?先说结论
不能直接、安全、可维护地用触发器实现多维报表的实时预聚合。这不是语法限制,而是架构层面的风险:触发器在事务内同步执行,一旦聚合逻辑变重(比如涉及多表 JOIN、GROUP BY 多维、写入汇总表时加锁),会显著拖慢主业务 DML(INSERT/UPDATE/DELETE),甚至引发死锁或长事务阻塞。生产环境里见过太多因 AFTER INSERT 触发器调用 INSERT INTO summary_table ... SELECT ... GROUP BY a,b,c 导致订单写入延迟从 20ms 涨到 2s 的案例。
为什么 INSERT 触发器一跑聚合就容易卡住
核心问题在于事务可见性与锁竞争:
INSERT 触发器一跑聚合就容易卡住
核心问题在于事务可见性与锁竞争:
• 主表写入和触发器里的聚合写入(如汇总表)处于同一事务,MySQL/PostgreSQL 对目标汇总表的 INSERT ... SELECT 会持有行级锁或间隙锁,阻塞其他维度的聚合写入;
• 多维组合(比如 region, product_type, time_month)意味着每次插入都可能更新几十上百个汇总行,触发器无法批量合并;
• 触发器无法感知“重复聚合”——同一事实行被 UPDATE 多次,触发器会反复计算,而真正需要的是“差值更新”;
• PostgreSQL 中 BEFORE 触发器不能读取新行之外的数据,MySQL 不支持语句级触发器,导致无法跨行做增量判断。
替代方案:用物化视图或异步任务更靠谱 不是放弃实时性,而是换更可控的路径:
• PostgreSQL 14+ 可用 REFRESH MATERIALIZED VIEW CONCURRENTLY 配合定时作业(如每分钟一次),它不锁源表,且支持增量刷新逻辑(需自定义);
• MySQL 没原生物化视图,但可用 REPLACE INTO summary_table SELECT ... FROM fact_table WHERE updated_at > ? + 维护一个 last_refresh_time 表,由外部调度器(如 Airflow 或 cron 调用 stored procedure)驱动;
• 关键点:把“聚合时间窗口”显式切分(如按小时分区),只刷上一小时的增量,避免全表扫描;
• 如果真要强一致,用 CDC(如 Debezium)捕获 binlog,将变更发到 Kafka,再由 Flink 或轻量服务消费并更新 Redis / OLAP 表——这已脱离 SQL 触发器范畴,但稳定得多。










