【问题标题】:How to find out why the status of a spid is suspended? What resources the spid is waiting for?如何找出 spid 的状态为何被挂起? spid 正在等待什么资源?
【发布时间】:2014-03-29 02:55:52
【问题描述】:

我运行EXEC sp_who2 78 并得到以下results

我怎样才能找到它的状态为何被暂停?

这个过程是一个沉重的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 张图片以适应屏幕)

【问题讨论】:

    标签: sql sql-server optimization query-optimization sql-tuning


    【解决方案1】:

    暂停: 这意味着该请求当前处于非活动状态,因为它正在等待资源。资源可以是一个读取页面的I/O,一个WAIT可以是网络上的通信,也可以是等待锁或闩锁。一旦它等待的任务完成,它将变为活动状态。例如,如果查询已发布 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 
    

    请以下图为例:

    【讨论】:

    • 感谢 SQL sn-p 非常有用!
    【解决方案2】:

    我使用 sp_whoIsActive 来查看此类信息,因为它是一个现成的免费工具,可为您提供解决慢查询问题的良好信息:

    How to Use sp_WhoIsActive to Find Slow SQL Server Queries

    通过这个,您可以获得查询文本、它正在使用的计划、查询正在等待的资源、阻塞它的原因、它取出的锁等等。

    比自己动手要容易得多。

    【讨论】:

      【解决方案3】:

      您可以通过以下方式解决它:

      1. 修复集群索引。
      2. 使用临时表获取所有表的一部分并使用它。

      我对具有 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-12
        相关资源
        最近更新 更多