如何找出spid状态暂停的原因? spid在等待什么资源?

时间:2014-02-26 10:34:38

标签: sql sql-server sp-who2

我运行EXEC sp_who2 78并获得以下结果:

results of sp_who2 for spid 78

如何找到暂停状态的原因?

此过程基于昂贵的查询而过重INSERT。一个很大的SELECT,它从几个表中获取数据,并将大约3-4百万行写入不同的表。

没有锁/块。

链接到的waittypeCXPACKET。我可以理解,因为你可以在下面的图片中看到9 78个。

关注我和我真正想知道的是为什么SPID 78的数字1被暂停。

我理解当暂停SPID的状态时,意味着进程正在等待资源,并且当资源获取资源时它将恢复。

如何找到更多有关此内容的详细信息?什么资源?为什么不可用?

我使用了下面的代码及其变体,但我还能做些什么来找出SPID被暂停的原因吗?

select * 
from sys.dm_exec_requests r
join sys.dm_os_tasks t on r.session_id = t.session_id
where r.session_id = 78

我已经使用过sp_whoisactive了。我得到的这个特殊spid78的结果如下:(分成3个图片以适应屏幕)

enter image description here

3 个答案:

答案 0 :(得分:30)

SUSPENDED: 这意味着当前请求未处于活动状态,因为它正在等待资源。资源可以是用于读取页面的I / O,WAITit可以是网络上的通信,或者它正在等待锁定或锁存。一旦等待的任务完成,它将变为活动状态。例如,如果查询已发布I / O请求以读取完整表tblStudents的数据,则此任务将暂停,直到I / O完成。一旦I / O完成(表tblStudents的数据在内存中可用),查询将进入RUNNABLE队列。

因此,如果它正在等待,请检查wait_type列以了解它正在等待什么,并根据wait_time进行故障排除。

我开发了以下过程来帮助我解决这个问题,它包括WAIT_TYPE。

use master
go

CREATE PROCEDURE [dbo].[sp_radhe] 

AS
BEGIN

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

SELECT es.session_id AS session_id
,COALESCE(es.original_login_name, '') AS login_name
,COALESCE(es.host_name,'') AS hostname
,COALESCE(es.last_request_end_time,es.last_request_start_time) AS last_batch
,es.status
,COALESCE(er.blocking_session_id,0) AS blocked_by
,COALESCE(er.wait_type,'MISCELLANEOUS') AS waittype
,COALESCE(er.wait_time,0) AS waittime
,COALESCE(er.last_wait_type,'MISCELLANEOUS') AS lastwaittype
,COALESCE(er.wait_resource,'') AS waitresource
,coalesce(db_name(er.database_id),'No Info') as dbid
,COALESCE(er.command,'AWAITING COMMAND') AS cmd
,sql_text=st.text
,transaction_isolation =
    CASE es.transaction_isolation_level
    WHEN 0 THEN 'Unspecified'
    WHEN 1 THEN 'Read Uncommitted'
    WHEN 2 THEN 'Read Committed'
    WHEN 3 THEN 'Repeatable'
    WHEN 4 THEN 'Serializable'
    WHEN 5 THEN 'Snapshot'
END
,COALESCE(es.cpu_time,0) 
    + COALESCE(er.cpu_time,0) AS cpu
,COALESCE(es.reads,0) 
    + COALESCE(es.writes,0) 
    + COALESCE(er.reads,0) 
    + COALESCE(er.writes,0) AS physical_io
,COALESCE(er.open_transaction_count,-1) AS open_tran
,COALESCE(es.program_name,'') AS program_name
,es.login_time
FROM sys.dm_exec_sessions es
    LEFT OUTER JOIN sys.dm_exec_connections ec ON es.session_id = ec.session_id
    LEFT OUTER JOIN sys.dm_exec_requests er ON es.session_id = er.session_id
    LEFT OUTER JOIN sys.server_principals sp ON es.security_id = sp.sid
    LEFT OUTER JOIN sys.dm_os_tasks ota ON es.session_id = ota.session_id
    LEFT OUTER JOIN sys.dm_os_threads oth ON ota.worker_address = oth.worker_address
    CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS st
where es.is_user_process = 1 
  and es.session_id <> @@spid
ORDER BY es.session_id

end 

下面的查询还可以通过显示spid正在等待的资源,显示在spid暂停时提供帮助的基本信息。

SELECT  wt.session_id, 
    ot.task_state, 
    wt.wait_type, 
    wt.wait_duration_ms, 
    wt.blocking_session_id, 
    wt.resource_description, 
    es.[host_name], 
    es.[program_name] 
FROM  sys.dm_os_waiting_tasks  wt  
INNER  JOIN sys.dm_os_tasks ot ON ot.task_address = wt.waiting_task_address 
INNER JOIN sys.dm_exec_sessions es ON es.session_id = wt.session_id 
WHERE es.is_user_process =  1 

请参阅下面的图片作为示例:

enter image description here

答案 1 :(得分:12)

我使用sp_whoIsActive查看此类信息,因为它是一个现成的免费工具,可为您提供有关缓慢查询疑难解答的良好信息:

How to Use sp_WhoIsActive to Find Slow SQL Server Queries

通过这个,您可以获得查询文本,它正在使用的计划,查询正在等待的资源,阻止它的内容,它正在取出的锁定以及更多内容。

比试图自己动手更容易。

答案 2 :(得分:0)

您可以通过以下方式解决问题:

  1. 修复群集索引。
  2. 使用时态表获取所有表的一部分并使用它。
  3. 我对一个有400,000,000行的表有同样的问题,并使用时态表来获取它的一部分然后我使用我的过滤器和内部因为更改索引不是一个选项。

    一些例子:

    --
    --this is need be cause DECLARE @TEMPORAL are not well for a lot of data.
    CREATE TABLE #TEMPORAL
    (
        ID BIGINT,
        ID2 BIGINT,
        DATA1 DECIMAL,
        DATA2 DECIMAL
    );
    
    WITH TABLE1 AS
    (
        SELECT
            L.ID,
            L.ID2,
            L.DATA
        FROM LARGEDATA L
        WHERE L.ID = 1
    ), WITH TABLE2 AS
    (
        SELECT
            L.ID,
            L.ID2,
            L.DATA
        FROM LARGEDATA L
        WHERE L.ID = 2
    ) INSERT INTO #TEMPORAL SELECT
        T1.ID,
        T2.ID,
        T1.DATA,
        T2.DATA
    FROM TABLE1 T1
        INNER JOIN TABLE2 T2
            ON T2.ID2 = T2.ID2;
    --
    --this take a lot of resources proces and time and be come a status suspend, this why i need a temporal table.
    SELECT
        *
    FROM #TEMPORAL T
    WHERE T.DATA1 < T.DATA2
    --
    --IMPORTANT DROP THE TABLE.
    DROP TABLE #TEMPORAL