MySQL默认不提供触发器执行日志,需通过SHOW TRIGGERS查看定义、查询information_schema.TRIGGERS获取状态,并在触发器内手动插入日志表记录执行情况。

怎么看阻塞链里有没有触发器参与
触发器不开启独立事务,它的锁会混在主 SQL 的 session_id 下,所以不能指望 sys.dm_exec_requests 直接标出“这是触发器”。得靠交叉验证:
- 查
sys.dm_tran_locks,找同时出现在多个表上的锁:比如主语句只操作orders,但某个会话还持有了audit_log的排它锁,而audit_log只在trg_after_insert_order里被写入,这就很可疑 - 用
sys.dm_exec_sql_text(sql_handle)反查阻塞方的原始语句——如果看到的是INSERT INTO orders,但它又锁了users表,立刻去查orders上有没有AFTER INSERT触发器更新users - 看
sys.dm_exec_trigger_stats里的total_elapsed_time:单次执行从 2ms 突增到 400ms,且时间点和阻塞高峰重合,说明触发器内部可能卡在慢查询或 I/O 上
MySQL 怎么用 SHOW ENGINE INNODB STATUS 快速抓触发器痕迹
死锁或长时间阻塞后立刻执行 SHOW ENGINE INNODB STATUS\G,重点盯 LATEST DETECTED DEADLOCK 或 TRANSACTIONS 区块:
-
mysql tables in use 2, locked 2:数字大于 1 就得警觉,说明不止一张表被卷入,大概率有触发器 - 堆栈里出现连续操作,比如
INSERT INTO orders后紧跟UPDATE audit_log,这就是触发器执行路径的铁证 -
HOLDS THE LOCK(S)和WAITING FOR THIS LOCK TO BE GRANTED中,若一把锁落在日志表、统计表(如t_log、summary_counter)上,基本坐实是触发器行为
SQL Server 用 DMV 定位触发器阻塞源的组合查询
单靠 sys.dm_os_waiting_tasks 不行,它只告诉你“等什么”,不说“谁加的”。真正有用的是这个组合:
SELECT r.session_id, r.status, r.command, r.wait_type, r.wait_time,
l.resource_type, l.resource_description, l.request_mode,
t.name AS trigger_name
FROM sys.dm_exec_requests r
JOIN sys.dm_tran_locks l ON r.session_id = l.request_session_id
LEFT JOIN sys.triggers t ON OBJECT_NAME(l.resource_associated_entity_id) = t.parent_class_desc
WHERE r.blocking_session_id <> 0;注意:t.parent_class_desc 并非总能匹配,所以别只依赖这一列;关键还是看 resource_description 是否指向触发器常操作的表,再结合 r.command 是 INSERT 却持有非主表锁来反推。
触发器里哪些写法会让阻塞变长甚至不可控
触发器共享主事务上下文,它做的任何事都会拖住整个事务。以下看似无害的操作,实际是阻塞放大器:
- 在触发器里调用远程 HTTP 接口(如
sp_OACreate):网络延迟直接卡住事务,锁一直不释放 -
INSERT INTO huge_audit_log这类大体积日志写入:I/O 慢 + 索引维护开销大,锁持有时间成倍延长 - 嵌套调用另一个含 DML 的存储过程,且没设
SET XACT_ABORT ON:异常时事务状态残留,锁无法自动清理 - 误用
IF @@TRANCOUNT = 0 BEGIN BEGIN TRAN END:在触发器里@@TRANCOUNT永远 ≥1,这个判断永远不成立,但开发者以为“安全”就放行了
最隐蔽的坑是锁范围失控:触发器里一条没走索引的 UPDATE product_stock SET qty = qty - 1 WHERE sku_code = 'ABC123',在 RR 隔离级别下可能升级为全表间隙锁,而另一事务按相反顺序操作,ABBA 锁序瞬间形成。排查必须回到执行计划,用真实参数跑 EXPLAIN 确认是否命中索引。


















