2014-02-26 64 views
26

我跑EXEC sp_who2 78,我得到下面的結果:如何找出爲什麼暫停spid的狀態? Spid等待什麼資源?

results of sp_who2 for spid 78

我如何才能找到爲什麼它的地位被暫停?

該過程是基於昂貴查詢的重型INSERT。一個大的SELECT,它從幾個表中獲取數據,並將大約3-4百萬行寫入不同的表。

沒有鎖/塊。

它連接的waittypeCXPACKET。我可以理解,因爲你可以在下面的圖片中看到9 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

回答

23

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

感謝您的SQL代碼段非常有用! – 99Sono

10

我用sp_whoIsActive看這樣的信息,因爲它是一個現成的免費工具,讓你良好的信息進行故障診斷慢查詢:

How to Use sp_WhoIsActive to Find Slow SQL Server Queries

有了這個,你可以得到的查詢文本,它使用什麼鎖定計劃,查詢正在等待的資源,是什麼阻止它,它是拿出和更多。

比試圖推出自己的產品要容易得多。

0

您可以到方式解決這個問題:

  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