sys.dm_exec_procedure_stats常看不到存储过程,因其仅显示自SQL Server启动或缓存清除后仍在缓存中且执行过的存储过程;WITH RECOMPILE、内存压力致计划被驱逐、权限不足或缓存重置均会导致缺失。

查 sys.dm_exec_procedure_stats 为什么经常看不到你的存储过程?
因为这个视图只保留「自上次 SQL Server 启动或计划缓存被清除后」有执行过且仍驻留在缓存中的存储过程统计。如果过程刚创建、执行完就被踢出缓存(比如内存压力大),或者用 WITH RECOMPILE 执行(不缓存执行计划),它就不会出现在这里。
- 确认是否真没执行:先在业务时段手动调一次
EXEC your_proc,再立刻查视图 - 检查缓存是否被清空过:运行
DBCC FREEPROCCACHE后所有记录都会消失 - 系统重启、故障转移、AG 切换都会重置该视图的计数器
- 注意权限:需要
VIEW SERVER STATE权限,否则返回空结果
怎么区分「高频但低耗」和「低频但高耗」的过程?
单看 execution_count 容易误判。真正影响系统的,往往是平均每次执行耗时长、逻辑读多、或总 CPU 消耗高的过程——哪怕一天只跑几次。
- 优先排序字段建议:
total_logical_reads / execution_count(平均逻辑读)、(total_worker_time / execution_count) / 1000.0(平均 CPU 毫秒) - 过滤掉测试/维护类过程:加
WHERE object_name(object_id, database_id) NOT LIKE 'sp_%' AND object_name(object_id, database_id) NOT LIKE 'usp_%_test%' -
last_execution_time比cached_time更能反映真实活跃度;后者只是计划加载时间
为什么 sys.dm_exec_procedure_stats 的时间单位是微秒?
SQL Server 内部所有时间统计(total_elapsed_time、total_worker_time 等)都以微秒(μs)为单位存储,直接除以 1000 得毫秒,除以 1000000 得秒。不转换单位就看数值会严重误估耗时。
- 常见错误写法:
SELECT total_elapsed_time FROM sys.dm_exec_procedure_stats→ 显示 245678900,其实是 245 秒,不是 245 毫秒 - 推荐计算方式:
CAST(total_elapsed_time / 1000000.0 AS DECIMAL(10,2)) AS [elapsed_sec] - 注意:
total_elapsed_time包含等待时间(如锁、IO),total_worker_time只算 CPU 时间,两者差值大说明存在明显阻塞或等待
想长期跟踪执行频率,但又不想每小时手动跑查询?
不能依赖 sys.dm_exec_procedure_stats 做长期趋势分析——它本身是易失性视图。必须把快照数据定期落库,再对比增量。
- 建一张归档表:
proc_stats_history,包含snapshot_time DATETIME2、object_id、execution_count、total_logical_reads等关键列 - 用 SQL Agent 作业每 15 分钟执行一次 INSERT SELECT,注意加
WHERE execution_count > ISNULL((SELECT MAX(execution_count) FROM proc_stats_history h WHERE h.object_id = s.object_id), 0)避免重复插入 - 别直接用
sys.dm_exec_procedure_stats做实时监控大盘:它不支持索引,大数据量下查询本身就慢,可能拖垮监控链路
缓存生命周期、单位混淆、缺乏持久化——这三个点卡住绝大多数人的分析起点。盯住它们,比堆复杂报表有用得多。

















