大规模高并发系统中不推荐使用sql触发器,因其在事务链、锁范围和可观测性三层面直接冲击稳定性:强制同步执行致批量操作串行化(1000行插入tps从1000骤降至1),隐式放大锁范围引发死锁,且完全脱离apm监控与慢日志追踪,导致问题不可见、不可调、不可控。

大规模高并发系统中不推荐使用 SQL 触发器,不是因为它写不出来,而是它会在事务链、锁范围和可观测性三个层面直接冲击系统稳定性——尤其当订单、库存、财务等核心表并发写入量达到每秒数百次时,一个 AFTER INSERT 触发器可能让 TPS 掉 30% 以上。
触发器强制同步执行,批量写入退化为串行操作
MySQL/PostgreSQL 的 FOR EACH ROW 触发器无法并行,1000 行批量插入就会调用 1000 次触发逻辑。哪怕每次只耗 1ms,总耗时就是 1 秒,TPS 从 1000 直接掉到 1。
- 常见错误现象:
SHOW PROCESSLIST中大量线程卡在Updating或Waiting for table metadata lock -
INFORMATION_SCHEMA.PROFILING显示触发器内 SQL 占总耗时 70%+,但EXPLAIN完全不展示这些语句 - 用
LOAD DATA INFILE导入 5 万行?触发器逐行执行,索引优化完全无效 - SQL Server 若未关闭
RECURSIVE_TRIGGERS,UPDATE同一表可能意外递归上千层
触发器隐式放大锁范围,极易引发死锁与等待链
主 DML 只锁一行,但触发器里一句 SELECT ... FOR UPDATE 就会额外持有一行甚至多行的 X 锁。多个并发事务交叉更新时,死锁几乎必然发生。
- 典型死锁场景:事务 A 在
orders触发器中更新users,事务 B 在users触发器中更新orders -
SHOW ENGINE INNODB STATUS显示trx_query是主 SQL,但阻塞源在触发器里那条没索引的SELECT - 触发器中查
inventory表若没建product_id索引,每次都是全表扫描 + 全表加锁 -
innodb_row_lock_waits指标飙升,但慢查询日志里找不到对应语句——因为触发器耗时不单独记录
触发器破坏分布式事务边界与可观测性
在分库分表(如 PolarDB-X、TiDB)、读写分离或多活架构下,触发器天然失效或引发重复执行,且完全脱离应用监控体系。
- PolarDB-X 报错
ERROR 1105 (HY000): Unsupported operation: cross-database trigger,同库跨分片也会强制协调器等待,把毫秒级事务拖到秒级 - ShardingSphere/MyCat 不解析触发器内部 SQL,硬编码表名如
UPDATE order_001会绕过分片路由规则 - 触发器只在主库执行,从库回放的是原始 DML ——
AFTER INSERT生成的审计记录在从库上根本不存在 - APM 工具抓不到触发器内执行的
INSERT INTO audit_log,slow_query_log里只看到主语句,800ms 耗时你根本看不出哪 720ms 花在没索引的SELECT上
真正该禁用的不是触发器语法,而是它的业务职责
很多“必须用触发器”的场景,数据库原生机制或应用层更轻、更稳、更可观测。
- 自动更新时间戳 → 用
TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,比触发器快 3–5 倍 - 字段校验 → 用
CHECK约束或应用层预检,失败更早、路径更清晰 - 跨表状态同步 → 改写
sync_event_log表 + Kafka 消费,而非AFTER INSERT直接UPDATE remote_table - 统计类更新 → 放弃实时
SUM,改用物化视图增量刷新或 Redis 原子计数 - 审计字段(如
created_by)必须由应用层显式传参,不要依赖@session_var或触发器读取连接上下文
最麻烦的不是触发器慢,而是你连它在哪慢都看不见;最危险的不是它做了什么,而是它做了什么你根本不知道。










