SQL Server 2014作业调用存储过程进入Suspended状态求助
老哥,这种突然掉链子还卡成Suspended状态的情况我碰过好多次,结合你的环境和描述,给你列几个优先级最高的排查方向,一个个来试,应该能找到根因:
1. 先抓等待类型(最核心的突破口)
你说会话状态是Suspended,但SQL Server里没有无理由的Suspended,背后一定对应具体的等待类型,这是定位问题的关键。赶紧跑这个SQL,找到你Job对应的会话:
SELECT s.session_id, s.status, s.wait_type, s.wait_time / 1000 AS wait_time_sec, s.wait_resource, t.text AS current_query FROM sys.dm_exec_sessions s JOIN sys.dm_exec_requests r ON s.session_id = r.session_id CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t WHERE s.program_name LIKE '%SQLAgent%' -- 过滤SQL Agent发起的会话,或者直接搜你的存储过程名称
重点看wait_type对应的场景:
- 如果是
RESOURCE_SEMAPHORE:说明内存不够用了——虽然你有64G,但可能其他进程占了大量内存,或者存储过程的查询计划因为统计信息过期,错误估算了内存需求,导致一直在等内存资源 - 如果是
ASYNC_NETWORK_IO:别被名字骗了,不一定是网络问题,也可能是存储过程里的中间结果需要返回给SQL Agent,但Agent那边处理慢(不过你说Idle98%,这个可能性稍低,但还是要排查) - 如果是
PAGEIOLATCH_*:哪怕你看到无读写,也可能是在等某个冷数据页加载到内存,比如维度表很久没被访问过,数据在磁盘上 - 如果是
CXPACKET:并行查询的协调等待,大概率是统计信息过期导致并行计划跑偏,比如本来应该用低并行度,结果选了高并行,导致线程间等待
2. 检查统计信息是否过期(高频坑)
SQL Server 2014对统计信息的依赖极强,尤其是多表关联的查询。如果周一之前你的维度表或事实表有大量数据变更(比如批量导入、删除),统计信息过期会让优化器生成完全错误的执行计划,直接导致各种奇怪的等待。
跑这个命令查相关表的统计信息状态:
SELECT t.name AS table_name, s.name AS stats_name, s.last_updated, s.rows AS total_rows, s.rows_sampled AS sampled_rows FROM sys.stats s JOIN sys.tables t ON s.object_id = t.object_id WHERE t.name IN ('维度表1', '维度表2', '你的事实表名') -- 替换成你实际用到的表 ORDER BY s.last_updated DESC;
如果last_updated是几周前的,或者sampled_rows远小于total_rows,赶紧更新统计信息:
UPDATE STATISTICS 你的表名 WITH FULLSCAN; -- 全量扫描更准确,数据量大的话可能慢,但值得
或者直接给存储过程加WITH RECOMPILE选项,强制生成新的执行计划试试:
EXEC 你的存储过程名 WITH RECOMPILE;
3. 排查临时表和tempdb的问题
你的存储过程用到了临时表,这也是常见的坑点:
- 临时表有没有建合适的索引?之前数据量小的时候全表扫描没影响,现在数据量大了,关联临时表时需要全扫,导致等待甚至卡死
- 临时表的统计信息滞后:SQL Server对临时表的统计信息更新不及时,尤其是多次插入数据后,可以手动更新:
UPDATE STATISTICS #你的临时表名; - tempdb的配置是否合理?6核CPU的话,tempdb应该配6个大小一致的数据文件(避免页闩锁争用)。跑这个命令查tempdb的等待情况:
SELECT wait_type, wait_time_ms / 1000 AS wait_time_sec, waiting_tasks_count FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGELATCH_%' AND wait_resource LIKE '2:%'; -- 2是tempdb的数据库ID
如果wait_time_sec很高,说明tempdb有严重的争用,赶紧调整数据文件数量。
4. 抓执行计划看异常操作
如果能重新跑存储过程(或者找到当时的执行计划),重点看这些异常点:
- 有没有
RID Lookup或Key Lookup:说明缺少覆盖索引,导致频繁回表查询 - 有没有
Sort操作且出现Warning: Operator used tempdb to spill data:排序内存不够,溢出到磁盘,会直接拖慢整个过程 - 并行度是否异常:比如明明数据量小,却用了最高并行度,导致线程等待
5. 检查SQL Server内存配置
虽然你有64G内存,但SQL Server的最大内存设置是不是合理?默认情况下SQL Server会占满所有内存,留给系统的内存太少,可能导致SQL Agent或其他进程异常。跑这个命令看:
SELECT name, value_in_use FROM sys.configurations WHERE name LIKE '%max server memory%';
如果value_in_use是0(默认),赶紧改成60416(约60G,单位是MB),留4G左右给系统,这个设置是动态生效的,不用重启SQL Server。
6. 排查磁盘的隐藏问题
你说磁盘剩余400G,但有没有可能是磁盘IO变慢?比如RAID卡缓存失效、磁盘碎片过多,或者磁盘本身有坏道?
- 用Windows的
性能监视器(perfmon)监控PhysicalDisk的Avg. Disk Sec/Read和Avg. Disk Sec/Write,如果超过20ms,说明磁盘IO有问题 - 查一下事实表和维度表的索引碎片:
SELECT t.name AS table_name, i.name AS index_name, avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ps JOIN sys.tables t ON ps.object_id = t.object_id JOIN sys.indexes i ON ps.object_id = i.object_id AND ps.index_id = i.index_id WHERE avg_fragmentation_in_percent > 30; -- 碎片超过30%需要整理
先从等待类型和统计信息这两个方向入手,大概率能找到问题。如果还是不行,再一步步排查其他点。
内容的提问来源于stack exchange,提问作者Obi Mark

