SQL Server查不到触发器真实耗时,只能通过sys.dm_exec_trigger_stats结合sys.triggers统计执行次数;MySQL必须手动埋点(如NOW(6)日志)才能获取耗时,二者均无法直接监控触发器独立资源消耗。

SQL Server 里查不到触发器的“真实耗时”,只能查它被调用了多少次;MySQL 则必须手动打点,否则连总耗时都看不到。
SQL Server 查触发器执行次数:用 sys.dm_exec_trigger_stats + sys.triggers
这个动态管理视图只缓存近期执行过的触发器,刚创建或重启后没被调用过的不会出现。它不记录单次耗时,但能告诉你累计调用了多少次、最后一次啥时候执行的。
-
execution_count是自上次 SQL Server 启动或该触发器重编译后的累计值,不是实时滚动计数 - 必须
JOIN sys.triggers才能把object_id映射成表名和触发器名,否则光看数字没法定位 - 结果为空?先确认触发器确实被 DML 语句触发过,再检查是否被
is_ms_shipped = 1过滤掉了(系统触发器默认不显示) - 嵌套调用也会被计入——比如一个触发器内部又 UPDATE 了另一张带触发器的表,那两个触发器的
execution_count都会加 1
示例查询:
SELECT t.name AS trigger_name,
OBJECT_NAME(t.parent_id) AS table_name,
s.execution_count,
s.last_execution_time
FROM sys.dm_exec_trigger_stats s
JOIN sys.triggers t ON s.object_id = t.object_id
WHERE s.execution_count > 0;
SQL Server 查触发器“实际耗时”:别查触发器,去查它挂靠的 DML 语句
触发器逻辑被内联编译进宿主语句(如 UPDATE Orders),所有 CPU、I/O、执行时间都算在那条语句头上。sys.dm_exec_trigger_stats 根本没有 cpu_time 或 logical_reads 字段。
- 用
sys.dm_exec_requests筛出长时间运行的请求,重点关注command IN ('INSERT', 'UPDATE', 'DELETE') - 结合
sql_handle提取完整 SQL,确认操作的表是否定义了触发器 -
total_elapsed_time > 500000(0.5 秒)在高并发 OLTP 环境已是风险信号 - 如果
logical_reads高但cpu_time低,大概率是触发器里做了没索引的 JOIN 或全表扫描
MySQL 查触发器执行次数和耗时:必须手动埋点
SHOW PROFILE 对触发器无效,它只显示外层语句耗时;slow_query_log 也不会标注“此慢因触发器导致”。想拿到真实数据,只能在触发器里插日志。
- 在触发器开头和结尾各写一条
INSERT INTO debug_log (ts, event),用NOW(6)记录微秒级时间戳 - 禁用
autocommit时,触发器和主语句共用事务 ID,INFORMATION_SCHEMA.INNODB_TRX查不到独立上下文 - 避免在触发器里直接
SELECT FROM same_table,MySQL 会隐式锁表甚至报错;真要查,先在主 SQL 里查好存进用户变量 - 务必检查
@@warning_count和SHOW WARNINGS,很多赋值失败、类型截断是静默的
通用陷阱:别被“执行了”骗过
看到 execution_count 猛增,或性能计数器里 Triggers/sec 拉高,不代表资源一定吃紧——可能只是轻量日志记录,也可能已拖垮系统。关键得看它挂靠的 DML 语句是否同步变重。
- SQL Server 里
Lock Waits/sec突升 +Batch Requests/sec下跌,大概率是触发器里事务太长或锁粒度太粗 - MySQL 开启慢日志后,得人工比对表结构和触发器定义,才能确认某条慢语句是否由触发器引发
- 所有数据库中,
BEFORE触发器里UPDATE同表极易引发死锁或递归,这种设计本身就要重构,监控只是补救手段

















