SQL Server无触发器专用DMV,需用性能计数器获取总次数/每秒速率,或用扩展事件捕获具体触发器的执行耗时与上下文。

SQL Server 本身不提供直接统计触发器调用次数或执行时长的系统视图,sys.dm_exec_procedure_stats 不包含触发器,sys.dm_exec_query_stats 也只记录独立语句,不会把触发器逻辑单独剥离出来计数。想拿到真实、可归因的触发器执行频率和耗时,必须绕过“看执行计划”这条路,转向更底层的信号采集方式。
为什么 sys.dm_exec_trigger_stats 不存在?
SQL Server 没有 sys.dm_exec_trigger_stats 这类专用 DMV。触发器的执行被“折叠”进其所属表的 DML 操作中:INSERT 触发器的开销算在 INSERT 语句的 total_elapsed_time 里,UPDATE 触发器的 CPU 时间混在 UPDATE 的 total_worker_time 中。你查不到“这个触发器被执行了 127 次”,只能看到“这张表上发生了 127 次 INSERT”。
- 触发器不是独立可缓存的执行单元,它没有自己的执行计划缓存条目(除非显式用
WITH RECOMPILE,但依然不单独计数) -
sys.dm_exec_requests能显示当前正在运行的触发器(command字段可能为EXECUTE TRIGGER),但仅限“此刻”,无法回溯历史频次 - 哪怕用
sys.fn_trace_gettable回放 Profiler 跟踪,也得提前开启并捕获SP:Starting/SP:Completed事件——而默认 trace 不包含触发器事件
唯一可靠路径:Performance Counter(性能计数器)
Windows 性能监视器(PerfMon)中的 SQL Server:General Statistics 对象提供了两个关键计数器:
-
Trigger Count:自 SQL Server 实例启动以来,**所有触发器被触发的总次数**(注意:是累计值,非每秒速率) -
Triggers/sec:**每秒触发的平均次数**(瞬时速率,需持续采样才能看出趋势)
这两个值可通过 T-SQL 直接读取:
SELECT cntr_value AS [trigger_total_count] FROM sys.dm_os_performance_counters WHERE object_name LIKE '%General Statistics%' AND counter_name = 'Trigger Count';
但要注意:
- 该计数器不区分触发器名称、所属表或类型(AFTER/INSTEAD OF),只给总数
- 它不提供任何耗时信息——
Triggers/sec是频率,不是毫秒级延迟 - 重启 SQL Server 后计数器清零,不能用于跨周期对比
要定位具体哪个触发器慢?必须结合扩展事件(XEvent)
如果目标是“找出 trg_orders_after_insert 平均每次执行超过 50ms”,性能计数器完全无能为力。此时唯一可行方案是创建轻量级 XEvent 会话,捕获 sqlserver.module_end 事件,并过滤 object_type = 'TR':
CREATE EVENT SESSION [track_triggers] ON SERVER
ADD EVENT sqlserver.module_end(
WHERE ([object_type] = 'TR')
AND ([duration] > 50000)) -- 单位是微秒,50ms = 50000
ADD TARGET package0.event_file(SET filename=N'trigger_slow.xel');启用后,可从 .xel 文件中提取:object_name、duration、statement(触发器内第一条语句)、client_app_name 等字段。这是目前唯一能把“谁、什么时候、花了多久、由哪条 INSERT 带动”串起来的方式。
- 别用 Profiler:开销大,生产环境禁用;XEvent 开销低且可精准过滤
- 避免捕获
rpc_completed或sql_batch_completed:它们不暴露触发器层级 - duration 字段单位是微秒,直接除以 1000 得毫秒,不转换单位会误判成 10 倍以上耗时
真正难的从来不是“怎么查”,而是“如何把触发器执行行为从主 DML 中解耦出来”。性能计数器只给总量,XEvent 才给明细——但后者需要提前部署、持续收集、定期解析。没有银弹,只有取舍。


















