sys.dm_exec_trigger_stats提供触发器累计执行次数等统计,但仅缓存近期调用且需JOIN sys.triggers补全名称;fn_trace_gettable或XEvent可捕获具体触发时间点,后者为SQL Server 2016+推荐方案。

查 sys.dm_exec_trigger_stats 看累计执行次数
SQL Server 2008 及以后版本提供这个动态管理视图,直接暴露每个触发器的调用总数、平均耗时等核心指标。它不记录单次执行详情,但对频率统计足够高效。
常见错误现象:SELECT * 直接查该视图返回空——因为默认只缓存最近执行过的触发器,从未被调用或刚重启服务的不会出现;另外,它不包含已删除但残留元数据的触发器。
- 必须用
JOIN sys.triggers补全触发器名称和所属表信息,否则object_id难以定位 - 结果中
execution_count是自上次 SQL Server 启动或该触发器被重新编译后的累计值,不是实时滚动计数 - 若需长期趋势,得定期采样写入自定义日志表,不能依赖该 DMV 持久保存
SELECT t.name AS trigger_name, OBJECT_NAME(t.parent_id) AS table_name, s.execution_count, s.total_elapsed_time / s.execution_count AS avg_duration_ms FROM sys.dm_exec_trigger_stats s JOIN sys.triggers t ON s.object_id = t.object_id WHERE s.execution_count > 0;
用 sys.fn_trace_gettable 捕获具体触发时间点
当需要知道“哪条语句在什么时候触发了哪个触发器”,就得启用跟踪(Trace)或扩展事件(XEvent)。SQL Server 2016+ 推荐用 XEvent,但老环境仍常见用 fn_trace_gettable 读取本地 trace 文件。
使用场景:排查某张表的触发器是否被意外高频调用,比如发现 execution_count 突增,但不知道是哪个应用、哪个时间段、哪类操作导致的。
-
fn_trace_gettable只能读取已停止或关闭的 trace 文件,运行中的 trace 不可见 - 触发器相关事件是
SP:Starting和SP:Completed,过滤时要加EventClass IN (43, 45),且ObjectType = 8048(表示触发器) - trace 文件体积增长快,未设轮转易占满磁盘;建议只开短时捕获,目标明确再停
注意触发器嵌套与递归调用带来的计数偏差
sys.dm_exec_trigger_stats.execution_count 统计的是所有上下文下的执行,包括由其他触发器引发的嵌套调用、自更新触发的递归调用。这会导致数值远高于业务语句数量。
容易踩的坑:看到某个触发器 execution_count 是主表 DML 语句的 5 倍,就断定有性能问题——其实可能是它内部又更新了关联表,触发了二级触发器,而二级触发器又被计入同一张统计表。
- 检查
sp_configure 'nested triggers'是否为 1(默认开启),关闭可阻断嵌套,但可能破坏原有逻辑 - 在触发器开头加
IF TRIGGER_NESTLEVEL() > 1 RETURN可主动跳过嵌套层,避免重复工作 -
sys.trigger_events能查出触发器响应哪些事件(INSERT/UPDATE/DELETE),但不反映嵌套深度
SQL Server 2016+ 优先用扩展事件替代 Trace
Trace 已被标记为“弃用”,fn_trace_gettable 在未来版本可能移除。扩展事件(XEvent)更轻量、可过滤强、支持异步文件目标,适合长期监控触发器调用。
关键配置项:sqlserver.sp_statement_completed 事件 + WHERE [object_type] = 'TR'(TR 表示触发器),配合 collect_statement 开关可捕获原始调用语句。
- XEvent 默认不收集触发器名,需手动添加
sqlserver.database_name、sqlserver.object_name等动作字段 - 事件会话设成
STARTUP = ON才能在服务重启后持续运行,否则每次都要手动启 - 用
sys.dm_xe_session_targets查当前输出路径,避免写错filename导致日志丢失
复杂点在于事件筛选表达式语法略拗口,而且不同 SQL Server 小版本对 object_name 字段的填充稳定性不一致——有时为空,得靠 object_id 关联 sys.objects 回填。










