sql server和mysql均无法直接监控触发器单次耗时与真实执行次数:sql server的sys.dm_exec_trigger_stats仅提供累计值且非实时,mysql则完全缺乏触发器级性能视图,必须手动埋点并通过宿主dml语句间接排查。

SQL Server 和 MySQL 都无法直接监控触发器的单次耗时,执行次数也受限于缓存机制或需手动埋点——别指望 sys.dm_exec_trigger_stats 或 SHOW PROFILE 返回真实延迟。
SQL Server 查触发器执行次数:只看 sys.dm_exec_trigger_stats 不够
这个动态管理视图确实能返回 execution_count,但它不是“实时计数器”,而是自上次 SQL Server 启动或该触发器重编译后的累计值。刚创建、没被调用过、或被 is_ms_shipped = 1 过滤掉的系统触发器,都不会出现在结果里。
- 必须
JOIN sys.triggers才能把object_id映射成可读的trigger_name和table_name - 嵌套触发也会被计入——比如触发器 A 内部
UPDATE了带触发器 B 的表,A 和 B 的execution_count都会 +1 - 想长期追踪趋势?得自己写定时任务,把每次查询结果插入日志表,不能依赖 DMV 持久保存
- 示例语句中除
execution_count外,total_elapsed_time / execution_count算出的“平均耗时”是误导性的:它实际是宿主 DML 语句的总耗时均值,触发器逻辑已被内联进主语句,没有独立 CPU 或 I/O 统计
MySQL 根本没有触发器级性能视图:必须手动打点
SHOW PROFILE 对触发器无效,slow_query_log 也不会标注“慢因触发器”。你看到的只是外层 INSERT/UPDATE 的耗时,里面跑了 10 层子查询还是 3 个触发器,日志一概不提。
- 唯一可靠方式是在触发器开头和结尾各插一条
INSERT INTO debug_log (ts, event),用NOW(6)记录微秒级时间戳 - 禁用
autocommit时,触发器与主语句共用事务 ID,INFORMATION_SCHEMA.INNODB_TRX查不到触发器单独上下文 - 别在触发器里写
SELECT NOW(6)就完事——要确保debug_log表有索引,例如CREATE INDEX idx_ts_event ON debug_log(ts, event),否则高并发下日志写入本身成瓶颈 - BEFORE 触发器里记录起点、AFTER 里算差值?不可靠。MySQL 不允许 BEFORE 中赋值给 NEW 字段再在 AFTER 中读取,两个作用域隔离,没有共享变量机制
定位慢触发器:别查触发器,去查它挂靠的 DML
触发器没有独立资源消耗视图。它的 CPU、逻辑读、执行时间全算在外层语句头上。真要排查,得从宿主语句入手:
- 用
sys.dm_exec_requests筛command IN ('INSERT', 'UPDATE', 'DELETE')且total_elapsed_time > 500000(0.5 秒)的请求 - 通过
sql_handle提取完整 SQL,确认操作的表是否定义了触发器 - 若
logical_reads高但cpu_time低,大概率是触发器里做了没索引的 JOIN 或全表扫描 - MySQL 下同理:先用
slow_query_log定位慢语句,再人工检查该表是否有触发器;别幻想触发器能自动上报“我拖慢了”
复杂点在于:你永远分不清是触发器慢,还是它调用的逻辑慢
一个 AFTER UPDATE 触发器里执行 UPDATE summary_table SET total = (SELECT SUM(amount) FROM detail WHERE ...),耗时来源可能是子查询没走索引、detail 表锁竞争、甚至 summary_table 自身被其他事务阻塞——而所有这些,在数据库性能视图里都堆在同一个“UPDATE users”语句名下。你看到的数字,从来不是触发器的,而是整个执行链路的。










