sys.dm_os_waiting_tasks 显示当前正在等待资源的任务快照,重点关注 wait_type(如 pageiolatch_*、resource_semaphore)、blocking_session_id 及 wait_duration_ms,用于定位存储过程“此刻”卡在何处;它不反映历史累计,需结合 sys.dm_os_wait_stats 分析长期内存压力趋势。

直接看 sys.dm_os_waiting_tasks 找出存储过程正在等什么内存资源
存储过程本身不“等内存”,它等的是被内存压力拖慢的下游操作:比如等待页从磁盘读入缓冲池(PAGEIOLATCH_*),或等待锁释放(LCK_M_*)而间接卡在内存分配路径上。真正反映内存相关等待的,是那些因内存不足、缓存争用、闩锁竞争引发的等待类型。执行以下查询能快速定位当前正在发生的内存敏感等待:
- 只查非空闲、非后台任务:
WHERE session_id > 50 AND wait_duration_ms > 0 - 重点关注
wait_type包含LATCH_*(如LATCH_EX)、PAGEIOLATCH_*、RESOURCE_SEMAPHORE、CMEMTHREAD的行 -
blocking_session_id非 0 表示它正被另一个会话阻塞,需顺藤摸瓜查源头
注意:sys.dm_os_waiting_tasks 是瞬时快照,不是历史累计——它告诉你“此刻卡在哪”,不是“过去总共卡了多久”。如果查不到,不代表没发生,可能刚结束或还没排队。
用 sys.dm_os_wait_stats 看累积趋势,识别长期内存压力信号
当怀疑存储过程反复遭遇内存瓶颈(比如每次执行都慢且波动大),就要看累计统计。运行:
SELECT wait_type, waiting_tasks_count, wait_time_ms, max_wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type IN ('PAGEIOLATCH_SH', 'PAGEIOLATCH_EX', 'RESOURCE_SEMAPHORE',
'CMEMTHREAD', 'SOS_SCHEDULER_YIELD', 'LATCH_EX')
ORDER BY wait_time_ms DESC;
关键判断点:
-
RESOURCE_SEMAPHORE高 → 查询编译/执行计划缓存申请内存失败,常见于并发大查询或未参数化 SQL -
CMEMTHREAD高 → 多个线程争抢同一内存对象(如编译器缓存条目),说明计划重用率低或存在大量即席查询 -
PAGEIOLATCH_*持续占前 3 → 缓冲池不够用,物理 I/O 频繁,本质是内存不足导致页无法常驻 -
SOS_SCHEDULER_YIELD高但signal_wait_time_ms占比低 → CPU 真忙;占比高则说明线程就绪后等调度太久,可能是 NUMA 节点间内存访问不均
别忘了用 DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR) 清零后观察特定窗口内的新增等待,避免被历史噪声干扰。
结合 sys.dm_exec_query_memory_grants 查看该存储过程实际拿到了多少内存
一个存储过程是否真被内存卡住,最直接证据是它申请的执行内存(grant)迟迟没批下来,或者批了但远低于预期。运行:
SELECT session_id, request_time, grant_time, requested_memory_kb,
granted_memory_kb, required_memory_kb, used_memory_kb,
max_used_memory_kb, query_cost, degree_of_parallelism
FROM sys.dm_exec_query_memory_grants g
JOIN sys.dm_exec_requests r ON g.session_id = r.session_id
WHERE r.command = 'EXECUTE' AND r.sql_handle IS NOT NULL;
重点看这几列:
-
granted_memory_kb为 0 或远小于requested_memory_kb→ 内存授予被拒绝或严重缩水,RESOURCE_SEMAPHORE等待大概率已发生 -
used_memory_kb接近granted_memory_kb但max_used_memory_kb还在涨 → 可能触发了内存溢出到 tempdb(spill),查sys.dm_exec_query_profiles确认 spill 位置 -
degree_of_parallelism= 1 但query_cost> 5 → 并行度被抑制,常见原因包括内存不足、cost threshold 配置过低、或 MAXDOP 设置为 1
这个 DMV 只显示已获得内存授予的请求,如果存储过程连授予都没拿到(比如卡在编译阶段),它不会出现在这里——此时要回头盯 sys.dm_os_waiting_tasks 和编译等待(ASYNC_IO_COMPLETION、WAITFOR 除外)。
别漏掉 NUMA 节点和内存节点分布不均的问题
SQL Server 2022 默认启用 soft-NUMA,但若底层硬件是多路 CPU + 非统一内存访问架构,而 sys.dm_os_memory_nodes 显示某节点 virtual_memory_committed_kb 远高于其他节点,或 sys.dm_os_nodes 中某个节点 online_scheduler_count 为 0,就说明内存分配出现倾斜。这种不均会导致:
- 部分调度器持续
RESOURCE_SEMAPHORE等待,而其他节点内存空闲 -
CMEMTHREAD在高并发下集中爆发,因为所有线程试图访问同一个内存 clerk - 即使总内存充足,存储过程仍频繁触发
PAGEIOLATCH—— 因为本地节点 buffer pool 不够,被迫跨节点访问
验证方法:对比 SELECT node_id, virtual_memory_committed_kb FROM sys.dm_os_memory_nodes 和 SELECT node_id, memory_node_id, online_scheduler_count FROM sys.dm_os_nodes。若发现节点 0 占用 90% 内存但只有 4 个 scheduler,而节点 1 有 8 个 scheduler 却几乎没内存,就是典型的 NUMA 绑定失衡。此时需检查启动参数 -g、max server memory 是否合理,以及是否启用了 soft-NUMA 自动拆分(sys.dm_os_sys_info 中 softnuma_configuration = 1)。











