SQL Server应监控挂靠的DML语句而非触发器本身,因资源消耗全计入宿主语句;MySQL需手动埋点结合日志定位,通用陷阱包括死锁风险、隐式锁表及静默错误,深层分析依赖扩展事件或performance_schema。

SQL Server:别查触发器本身,去查它挂靠的 DML 语句
SQL Server 根本不给触发器单独记 CPU、I/O 或执行时间——sys.dm_exec_trigger_stats 只有 execution_count 和 last_execution_time,没有 cpu_time、logical_reads 这类字段。你查它等于白查。
触发器逻辑被内联编译进宿主语句(比如一条 UPDATE Orders),所有资源消耗都算在那条语句头上。所以监控对象必须是 DML,不是触发器。
- 用
sys.dm_exec_requests筛出长时间运行的请求,重点关注command IN ('INSERT', 'UPDATE', 'DELETE'),再结合sql_handle提取完整 SQL,确认是否操作了带触发器的表 -
total_elapsed_time > 3000000(3 秒)是常用阈值,但高并发 OLTP 环境建议压到 500000(0.5 秒) - 如果
logical_reads高但cpu_time低,大概率是触发器里做了没索引的 JOIN 或全表扫描
MySQL:靠打点 + 日志,别信 SHOW PROFILE
SHOW PROFILE 对触发器无效——它只显示外层语句耗时,根本看不到触发器内部哪一行卡住。想定位慢点,只能手动埋点。
在触发器开头和结尾写入微秒级时间戳,比如:
INSERT INTO debug_log (id, ts, event) VALUES (UUID(), NOW(6), 'before_update');
再查差值,就能知道触发器整体耗时;配合多点插入,还能二分定位瓶颈位置。
- 禁用
autocommit时,触发器和主语句共用事务 ID,INFORMATION_SCHEMA.INNODB_TRX查不到独立上下文 - 避免在触发器里直接
SELECT FROM same_table,MySQL 会报错或隐式锁表;真要查,先在主 SQL 里查好存进用户变量,再传进触发器 - 检查
@@warning_count和SHOW WARNINGS,很多赋值失败、类型截断是静默的,数据就错了还不报错
通用陷阱:别被“触发器执行了”骗过
看到 Number of Triggers Fired 在 PerfMon 里飙升,或 sys.dm_exec_trigger_stats 显示调用次数猛增,不代表资源一定吃紧——可能只是轻量级日志记录,也可能已经拖垮系统。关键看它挂靠的语句是否同步变重。
- SQL Server 里
Lock Waits/sec突升 +Batch Requests/sec下跌,大概率是触发器里事务太长或锁粒度太粗 - MySQL 开启
slow_query_log时,慢日志只记主语句,不会标出“此慢因触发器导致”,得人工比对表结构和触发器定义 - 所有数据库里,触发器修改同表(尤其是 BEFORE 触发器里 UPDATE 自己)都极易引发死锁或递归,这种设计本身就要重构,监控只是暴露问题,不是解决方案
扩展事件 / performance_schema 是唯一能抓全程的手段
DMV 和慢日志都是采样或事后记录,想拿到单次触发器执行的完整资源轨迹(比如 CPU 时间、等待类型、I/O 分布),必须上更底层的采集工具。
SQL Server 用扩展事件捕获 sql_batch_completed 和 sp_statement_completed,过滤 sql_text 包含目标表名,就能关联到具体触发动作;MySQL 则打开 performance_schema 的 statement 和 wait 仪器,查 events_statements_history_long 和 events_waits_history_long。
- 扩展事件默认不收集
cpu_time字段,需手动勾选;MySQL 的TIMER_WAIT单位是皮秒,除以1000000000才是毫秒 - 这类采集开销不小,生产环境建议只对怀疑表开启,持续跑全库会显著增加内存压力
- 最常被忽略的一点:触发器里调用的 UDF、外部函数、链接服务器查询,其资源消耗也会计入父语句——但执行计划里未必体现,得靠扩展事件/PS 的 wait 事件反推

















