mysql触发器并发压测必须显式控制事务边界,统一begin/rollback,否则无法捕获中间态、new/old修改及异常;其延迟呈指数级恶化,且易因跨表操作、嵌套触发引发死锁或error 1442报错。

触发器并发压测必须绕过框架自动提交
默认用 Python/Java 测试框架直接 INSERT 后查表,根本测不出触发器真实行为——因为事务已自动 COMMIT,中间态、异常拦截、NEW/OLD 修改都不可见。所有测试必须显式控制事务边界。
- MySQL 测试开头统一执行
BEGIN,结尾强制ROLLBACK;别依赖autocommit=1下的“插入即生效”假象 - PostgreSQL 可用
SAVEPOINT嵌套验证链式触发(比如AFTER INSERT→ 再INSERT日志表 → 触发另一张表的BEFORE UPDATE),MySQL 5.7 及更早版本只能靠单事务回滚,多步逻辑易串扰 - 验证
BEFORE触发器是否改写了NEW.amount,不能等事务结束再查最终值,得在INSERT后立刻SELECT amount FROM t WHERE id = ?抓中间态
压测时触发器延迟不是线性增长,而是指数级恶化
每秒 100 次写入加一个触发器,单条 INSERT 可能只慢 0.3ms;但升到 2000 QPS,延迟常翻 3 倍以上。这不是 CPU 算不过来,而是锁竞争、binlog 日志刷盘、事务日志缓冲区争用同步放大。
- 用
SYSBENCH或自建脚本对比「有触发器」和「注释掉触发器体」的INSERT p95延迟,别只看平均值——拐点往往出现在 p95/p99 - 触发器里含
SELECT FROM other_table是最大雷区:哪怕查的是缓存表,没加WHERE id = NEW.x_id这种强过滤,就会扫全表或触发索引失效,QPS 上去后直接拖垮 - 主从延迟飙升常源于触发器里的
UPDATE:主库生成额外 binlog 事件,从库必须串行回放;检查binlog_format必须是ROW,MIXED或STATEMENT下行为不可预测
嵌套触发与跨表更新极易引发死锁或报错
MySQL 8.0+ 在触发器里 UPDATE 同一张表会直接报 ERROR 1442 (HY000);SQL Server 批量更新 100 行时,嵌套触发器让耗时从 150ms 暴涨到 3200ms,死锁率升至 23%。
- 禁止在
orders的AFTER INSERT里再UPDATE orders—— 这不是性能问题,是语法硬限制 - 跨表逻辑(如订单插入后扣库存)必须拆出:应用层异步发 MQ,或定时任务补数据;别指望触发器“悄悄搞定”
- SQL Server 压测前执行
EXEC sp_configure 'nested triggers', 0; RECONFIGURE;关闭嵌套,否则单语句可能触发十几层递归
触发器异常会拖垮整个事务,但错误常被静默吞掉
触发器里 INSERT INTO log_table 因唯一键冲突失败,会导致父事务直接回滚——但如果你没在测试里捕获 SIGNAL SQLSTATE 或 RAISERROR,就只会看到“数据没插进去”,根本不知道是触发器崩了。
- MySQL 测试中主动用
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'simulated failure'注入失败,但注意:DECLARE HANDLER不会中断当前语句,得配合IF @error_flag THEN LEAVE proc_label; - PostgreSQL 测试必须包在
BEGIN ... EXCEPTION WHEN others THEN ... END块里,并用GET STACKED DIAGNOSTICS提取错误信息做断言 - 别在触发器里调用存储过程或函数处理日志——简单
INSERT INTO audit_log () VALUES (NEW.id, NOW(), USER())就够,函数调用开销在高并发下会被急剧放大
INSERT/UPDATE 上。你测的从来不是“触发器本身”,而是它如何把业务 SQL 拖进泥潭。










