应使用xevents(如sp_statement_completed)替代已弃用的sql server profiler,配合collect_statement_text=on获取语句,duration单位为微秒;存储过程内用sysdatetime()打点记录真实耗时,并通过dmv或查询存储交叉验证cpu与等待时间。

用扩展事件(XEvents)抓取真实耗时和CPU,别碰SQL Server Profiler
Profiler 已被微软明确弃用,2026年及以后版本将移除;它显示的 Duration 默认单位是微秒但界面常误标为毫秒,且包含网络延迟,无法区分“存储过程体内执行”和“客户端往返”。真实耗时必须用 sp_statement_completed 或 rpc_completed 事件,配合谓词过滤目标存储过程名。
关键实操点:
- 必须启用
collect_statement_text = ON,否则看不到实际执行语句,无法确认是不是你关心的那个EXEC GetEmployeeByID -
duration字段单位始终是微秒(不是毫秒),除以 1000 得毫秒,除以 1e6 得秒 - 避免用
sql_batch_completed:它捕获整批语句,无法定位单个存储过程体内的执行段 - 长期监控请输出到
event_file目标,别用ring_buffer(重启即丢,容量极小)
在存储过程内部用 SYSDATETIME() 打点记录耗时
这是最轻量、最可控的方式,不依赖外部跟踪,也不受连接或网络干扰。适用于需要长期埋点、做趋势分析或失败兜底的场景。
正确写法示例:
DECLARE @start_time datetime2 = SYSDATETIME();
-- 主逻辑:INSERT/UPDATE/复杂查询等
DECLARE @end_time datetime2 = SYSDATETIME();
INSERT INTO proc_execution_log (
proc_name,
start_time,
end_time,
duration_ms,
status,
error_msg
) VALUES (
OBJECT_NAME(@@PROCID),
@start_time,
@end_time,
DATEDIFF(ms, @start_time, @end_time),
'S',
NULL
);
注意:
- 用
SYSDATETIME(),别用GETDATE()(精度仅 3.3ms)或GETUTCDATE()(时区错位难对齐) - 务必把
INSERT放进TRY...CATCH的CATCH块里补失败记录,否则异常退出时日志就断了 - 日志表字段建议含
proc_name、start_time、end_time、duration_ms、status、error_msg
查实时会话和历史资源消耗,用 DMV 而不是 sp_Who2
sp_Who2 只返回会话快照,不含当前 SQL 文本、开始时间、等待类型或 CPU 累计值。真正能查到“正在执行的存储过程用了多少 CPU”的是动态管理视图。
常用组合:
-
sys.dm_exec_requests:查当前正在运行的请求,含start_time、cpu_time(毫秒)、command、sql_handle -
sys.dm_exec_sessions:查会话级累计 CPU(cpu_time)和内存使用 -
sys.dm_exec_query_stats:查缓存计划的历史统计,含total_worker_time(CPU 总耗时,微秒)、execution_count、avg_elapsed_time
快速定位高 CPU 存储过程的语句:
SELECT
t.text AS [sql_text],
qs.total_worker_time / 1000 AS [cpu_ms],
qs.execution_count,
qs.total_worker_time / qs.execution_count / 1000 AS [avg_cpu_ms]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
WHERE t.text LIKE '%GetEmployeeByID%'
ORDER BY qs.total_worker_time DESC;
不要忽略 Azure SQL DB 和查询存储的替代路径
如果你在 Azure SQL DB 上,Profiler 根本不可用(连不上),XEvents 是唯一官方支持的轻量跟踪方式。但更推荐直接启用查询存储(QUERY_STORE = ON),它自动捕获执行计划、运行时统计和等待信息,还能通过 Query Performance Insight 图形化查看 DTU 消耗分布。
启用后可直接查:
-
sys.query_store_runtime_stats:含avg_duration(纳秒)、avg_cpu_time(微秒)等 -
sys.query_store_plan+sys.query_store_query:按object_id关联到具体存储过程
注意:查询存储默认不捕获所有语句,首次启用后需等 15–30 分钟积累数据;若发现没记录,检查是否启用了 INTERVAL_LENGTH_MINUTES 和 MAX_PLANS_PER_QUERY 限制。
真实耗时最难的不是采集,而是区分“网络延迟”“锁等待”“计划重编译开销”和“纯执行时间”——XEvents 的 wait_info 字段、DMV 的 wait_type 和查询存储的 runtime_stats_interval 才是交叉验证的关键。











