sql_statement_completed事件必须加WHERE过滤(如[duration]>5000000),否则高并发下.xel文件几分钟达GB级;需结合object_name、显式捕获sql_text、设置MAX_DISPATCH_LATENCY等参数保障生产可用。

sql_statement_completed 事件必须加 WHERE 过滤,否则会撑爆磁盘
直接监听 sql_statement_completed 会捕获所有语句,包括系统内部调用、心跳查询、监控轮询——这些在高并发库上每秒几百上千条,.xel 文件几分钟就能涨到 GB 级。你真正要的只是“慢过程”,不是全部语句流。
正确做法是用微秒单位做硬过滤:SQL Server 内部 duration 字段单位是微秒(不是毫秒),5 秒超时对应 WHERE ([duration] > 5000000)。漏掉这个零,条件就失效;写成 > 5000,等于只抓 5 毫秒以上的语句,噪音爆炸。
- 别信 SSMS 图形界面里“持续时间 > 5000”的输入框——它默认按毫秒显示,但底层仍存微秒值,手动改脚本才靠谱
- 如果目标存储过程本身执行快,但被长事务阻塞导致整体耗时高,单靠
sql_statement_completed不够,得补wait_info或blocked_process_report - 文件目标路径必须是 SQL Server 服务账户有写权限的本地路径,网络 UNC 路径在多数生产环境会被静默丢弃
target_data 解析时注意 XML 截断和 plan_handle 缺失
扩展事件默认把 sql_text 和 plan_handle 作为可选 action 加进去,但它们不是总能拿到:参数化查询可能让 sql_text 变成 sp_executesql 的壳,而 plan_handle 在缓存被清空后就是空值。更麻烦的是,SQL Server 对 sql_text 字段有默认 4000 字符截断,长存储过程定义直接被砍头。
解决办法是显式启用大文本捕获,并用 T-SQL 解析时强制展开:
- 建会话时加
ACTION(sqlserver.sql_text, sqlserver.plan_handle, sqlserver.session_id),且确保没勾选“限制事件大小”类选项 - 解析
event_dataXML 时,用value('(/event/action[@name="sql_text"]/value)[1]', 'nvarchar(max)')而非text类型字段,避免隐式截断 - 若
plan_handle为空,别急着放弃——先查sys.dm_exec_cached_plans是否还在,再用sys.dm_exec_query_plan(plan_handle)提取执行计划
跟踪存储过程不能只盯 EXEC,得覆盖所有调用入口
业务代码里调用存储过程的方式五花八门:EXEC proc_name、EXECUTE proc_name、sp_executesql N'EXEC proc_name'、甚至 ORM 自动生成的包装语句。单纯过滤 sql_text LIKE '%proc_name%' 极易漏掉——比如过程名带下划线被当成通配符,或被注释包裹。
更稳的路径是结合上下文识别:
- 用
object_nameaction(需在 event 定义中显式添加)直接提取被调用对象名,它不依赖文本解析,稳定得多 - 如果过程是通过
sp_executesql执行的,sql_text里看不到过程名,但object_name仍能捕获到——前提是 SQL Server 版本 ≥ 2016 SP2,旧版本该字段为空 - 对加密存储过程,
sql_text固定返回NULL,此时唯一能定位的就是object_name+session_id+ 时间戳,配合sys.dm_exec_sessions查登录主机和应用名
长期运行会话必须设 MAX_DISPATCH_LATENCY 和 EVENT_RETENTION_MODE
想让扩展事件在后台默默跑一周?默认配置会让你失望。没设 MAX_DISPATCH_LATENCY,事件可能卡在内存缓冲区几十秒不落盘;没调 EVENT_RETENTION_MODE,一旦磁盘 IO 拥塞,新事件会被直接丢弃,日志出现大片空白。
生产级会话至少要压这三根弦:
-
MAX_DISPATCH_LATENCY = 30 SECONDS:平衡性能与实时性,低于 10 秒对高负载实例压力明显 -
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS:宁可丢一条,也不能卡住整个会话,比NO_EVENT_LOSS实际得多 -
MAX_EVENT_SIZE = 4096 KB:防止单条巨量日志(如含大 XML 执行计划)撑爆缓冲区,尤其当开启collect_database_name或collect_system_time时
这些参数不在 SSMS 图形界面里暴露,必须用 CREATE EVENT SESSION 脚本显式声明——点几下鼠标建的会话,上线前务必导出脚本检查。

















