查sys.dm_exec_procedure_stats是统计存储过程性能的唯一可靠起点,需满足已执行、计划在缓存、有VIEW SERVER STATE权限等前提,且须按库过滤、单位换算、排除系统过程,并注意其仅提供累计统计而非单次详情。

查 sys.dm_exec_procedure_stats 是唯一靠谱起点
直接查这个 DMV,别绕弯。它专为统计存储过程运行指标设计,但前提是过程已执行过、计划仍在缓存中、你有 VIEW SERVER STATE 权限。没权限会返回空,不是没数据。
- 必须加
WHERE database_id = DB_ID(N'YourDBName'),否则跨库混在一起,object_name(object_id, database_id)才能正确解析名称 - 时间字段单位是微秒,
total_elapsed_time除以1000000.0才是秒,不转就误判——比如显示8523456789是 8523 秒,不是 8.5 秒 - 优先看
(total_elapsed_time / execution_count) / 1000000.0(平均耗时秒),比单纯看execution_count更反映真实瓶颈 - 过滤掉系统过程:
AND object_name(object_id, database_id) NOT LIKE 'sp[_]%' AND object_name(object_id, database_id) NOT LIKE 'xp_%'
为什么刚改完的存储过程可能查不到?
不是查询写错了,是缓存机制在起作用。sys.dm_exec_procedure_stats 只记录「当前仍驻留在计划缓存中」且执行过的存储过程。以下情况会导致它消失:
- 过程用了
WITH RECOMPILE,每次执行都重新编译,不缓存计划 → 永远不会出现在该视图 - 内存压力大,SQL Server 主动驱逐了它的执行计划
- 有人执行过
DBCC FREEPROCCACHE或实例重启过 - 过程刚创建,还没被调用过
验证方法很简单:手动执行一次 EXEC YourProc @param = 'test',再立刻查视图,如果出现了,说明就是缓存问题。
想看单次最慢那次执行?得靠扩展事件
sys.dm_exec_procedure_stats 给的是累计统计,看不到某一次具体执行花了多久。要定位“单次最慢”的调用,必须用扩展事件(XEvent):
- 建一个轻量级会话,监听
rpc_completed事件,加WHERE object_name = N'YourProcName'过滤 - 捕获字段至少包括:
duration(微秒)、cpu_time、logical_reads、start_time、client_hostname - 别用
query_post_execution_showplan,开销太大,生产环境禁用;要执行计划就用rpc_completed+ 后续查sys.dm_exec_query_plan(plan_handle) - 事件数据默认存在内存里,记得配置目标(如
event_file)并定期归档,否则重启就丢
加密存储过程不影响耗时统计
哪怕过程定义用了 WITH ENCRYPTION,sys.dm_exec_procedure_stats 和扩展事件照样能完整记录它的执行次数、耗时、读取量、调用来源。SQL Server 在运行时解密后生成执行计划,所有性能数据都来自内存中的运行态,和源码是否可见无关。
真正容易被忽略的是:平均耗时低 ≠ 没问题。一个每天只跑 3 次、但单次逻辑读 500 万页的过程,可能比每秒跑 100 次、每次读 100 页的过程更伤 IO。盯住 total_logical_reads / execution_count 和 max_elapsed_time,比只看平均值管用得多。

















