web-dev-qa-db-de.com

Wie kann ich herausfinden, warum der Status eines Spid aufgehoben wird? Auf welche Ressourcen wartet der Spid?

Ich starte EXEC sp_who2 78 und erhalte folgende Ergebnisse:

results of sp_who2 for spid 78

Wie finde ich heraus, warum sein Status ausgesetzt ist?

Dieser Prozess ist ein schweres INSERT, das auf einer teuren Abfrage basiert. Ein großes SELECT, das Daten aus mehreren Tabellen abruft und 3-4 Millionen Zeilen in eine andere Tabelle schreibt.

Es gibt keine Sperren/Blöcke.

Das waittype, mit dem es verbunden ist, ist CXPACKET. Das kann ich verstehen, weil es 9 78er gibt, wie Sie auf dem Bild unten sehen können.

Was mich angeht und was ich wirklich gerne wissen würde, ist, warum die Nummer 1 der SPID 78 aufgehängt ist.

Ich verstehe, dass wenn der Status eines SPID ausgesetzt wird, bedeutet das, dass der Prozess auf eine Ressource wartet, und er wird wieder aufgenommen, wenn er seine Ressource erhält.

Wie finde ich weitere Details dazu? welche Ressource? warum ist es nicht verfügbar?

Ich verwende viel Code und Variationen hiervon, aber kann ich sonst noch etwas tun, um herauszufinden, warum die SPID ausgesetzt ist?

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

Ich habe bereits sp_whoisactive verwendet. Das Ergebnis, das ich für diesen speziellen Spid78 erhalte, ist wie folgt: (in 3 Bilder aufgeteilt, um den Bildschirm anzupassen)

enter image description here

30

SUSPENDED: Dies bedeutet, dass die Anforderung derzeit nicht aktiv ist, da sie auf eine Ressource wartet. Die Ressource kann eine E/A zum Lesen einer Seite sein. A WAITit kann die Kommunikation im Netzwerk sein oder auf eine Sperre oder eine Sperre warten. Es wird aktiv, sobald die Aufgabe, auf die es wartet, abgeschlossen ist. Wenn die Abfrage beispielsweise eine E/A-Anforderung zum Lesen von Daten einer vollständigen Tabelle TblStudents gesendet hat, wird diese Task angehalten, bis die E/A abgeschlossen ist. Sobald die E/A abgeschlossen ist (Daten für die Tabelle tblStudents sind im Speicher verfügbar), wird die Abfrage in die RUNNABLE-Warteschlange verschoben.

Wenn es wartet, überprüfen Sie die wait_type-Spalte, um zu verstehen, worauf es wartet, und beheben Sie die Problembehandlung anhand der wait_time.

Ich habe das folgende Verfahren entwickelt, das mir dabei hilft, es enthält den 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 

Die folgende Abfrage kann auch grundlegende Informationen anzeigen, die helfen, wenn das Spid angehalten wird, indem angezeigt wird, auf welche Ressource das Spid wartet.

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 

Bitte sehen Sie sich das Bild unten als Beispiel an:

enter image description here

29

Ich verwende sp_whoIsActive, um diese Art von Informationen anzuzeigen, da es sich um ein fertiges kostenloses Tool handelt, das Ihnen gute Informationen für die Problembehandlung bei langsamen Abfragen bietet:

So verwenden Sie sp_WhoIsActive zum Suchen langsamer SQL Server-Abfragen

Damit erhalten Sie den Abfragetext, den verwendeten Plan, die Ressource, auf die die Abfrage wartet, was sie blockiert, welche Sperren sie annimmt und vieles mehr.

Viel einfacher als zu versuchen, selbst zu rollen.

12
steoleary

Sie können es mit folgenden Möglichkeiten lösen:

  1. Korrigieren Sie den Clusterindex.
  2. Verwenden Sie temporale Tabellen, um einen Teil der Tabelle all zu erhalten und damit zu arbeiten.

Ich habe das gleiche Problem mit einer Tabelle mit 400.000.000 Zeilen und verwende temporäre Tabellen, um einen Teil davon zu erhalten. Dann verwende ich meine Filter und Inners, da das Ändern des Index keine Option war.

Einige Beispiele:

--
--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
0
Moises Conejo