压测触发器必须用并发dml而非单条sql,通过sysbench/pgbench模拟混合场景,监控锁等待指标,启用全量日志,用临时表记录触发器执行路径,避免非确定性函数和嵌套锁,重点测试字段组合边界与default字段影响。

用压测工具发并发DML,别只跑单条SQL
单条 INSERT 或 UPDATE 测不出触发器在真实高并发下的表现。锁等待、死锁、执行延迟这些风险,只有在多线程/多连接同时操作时才会暴露。
常见错误现象:本地用命令行手动插10次都成功,上线后每秒200个订单就频繁报 Deadlock found when trying to get lock 或 Lock wait timeout exceeded。
- 用
sysbench(MySQL)或pgbench(PostgreSQL)构造批量 DML 脚本,模拟 INSERT/UPDATE 混合场景 - 避免用应用层循环发请求——网络开销和连接池会掩盖数据库层真实压力,直接连 DB 执行更准
- 关键指标盯紧
Innodb_row_lock_waits(MySQL)或pg_stat_database.blk_write_time(PG),飙升说明锁竞争已成瓶颈 - 测试中必须开启慢日志和 general_log(MySQL)或
log_statement = 'all'(PG),确认触发器是否被反复调用或卡在某一行
在触发器里加轻量日志,但别写进主事务
想看清触发器到底执行了几次、在哪卡住,不能靠 SELECT 或 PRINT——它们不落盘,事务一回滚就消失。也不能直接往业务表或大日志表里 INSERT,否则会放大锁冲突。
- 建一张极简的临时日志表:
CREATE TEMP TABLE trigger_debug_log (ts TIMESTAMPTZ, event TEXT, row_id BIGINT)(PG)或CREATE TEMPORARY TABLE(MySQL) - 触发器内用
INSERT INTO trigger_debug_log ...记录关键路径,TEMP 表自动随会话销毁,不污染数据且无锁竞争 - 若必须持久化,改用异步方式:触发器只写一条轻量消息到
trigger_queue表(带索引),由外部消费者处理归档 - 严禁在触发器里调用
NOW()、UUID()等非确定性函数记录时间——会导致 binlog 不一致或复制延迟
用 SAVEPOINT 拆解多步验证,避开 MySQL 5.7 的事务限制
要验证一个 BEFORE UPDATE 触发器是否真修改了 NEW.status,又不影响后续断言,得在同个事务里分阶段观察。但 MySQL 5.7 不支持 SAVEPOINT 嵌套回滚,容易串扰。
- PG 和 SQLite 可安全用:
SAVEPOINT sp1; UPDATE ...; SELECT * FROM orders WHERE id = 123; ROLLBACK TO sp1; - MySQL 5.7 必须退回到完整事务控制:每个测试用例独占连接,
BEGIN开头、ROLLBACK结尾,中间穿插SELECT查当前行状态 - 别在触发器里做
SELECT ... FOR UPDATE后再UPDATE——这等于提前加锁,而你的测试事务还没真正开始,PG 下极易引发“锁已持有时主SQL才启动”的错觉 - 对链式触发(A表触发B表,B表又触发A表),测试前先
SET SESSION max_sp_recursion_depth = 0(MySQL)或SET LOCAL session_replication_role = 'replica'(PG)临时禁用,定位主干逻辑
重点测字段组合边界,不是空值或长度
高并发下出问题的,往往不是“插入 NULL”,而是特定字段组合触发了隐式锁升级或条件误判。比如一个库存扣减触发器只响应 status = 'paid' 且 qty > 0,那就要专门构造并发场景测:
-
UPDATE orders SET status = 'paid', qty = 1 WHERE id IN (1,2,3)—— 多行同时命中,看是否锁住整个索引范围 -
UPDATE orders SET status = 'paid', updated_at = NOW() WHERE id = 1—— 其他字段变更是否干扰触发器判断(尤其当触发器含IF NEW.updated_at != OLD.updated_at) - 批量导入时用
LOAD DATA INFILE,确认触发器是否按行触发(MySQL 是),且OLD/NEW是否始终为单行上下文 - 别漏掉 DEFAULT 字段:如
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,触发器读NEW.created_at可能是 NULL,而非预期的默认值
高并发验证最难的不是造压,而是把“触发器执行了”和“它没拖垮整个事务”这两件事拆开看清楚。多数人卡在日志没落盘、锁没释放、或者边界组合根本没想到——结果压测报告一切正常,上线后第一波流量就卡死。











