Comment savoir pourquoi le statut d'un spid est suspendu ?Quelles ressources le spid attend-il ?
-
21-12-2019 - |
Question
je cours EXEC sp_who2 78
et j'obtiens ce qui suit résultats:
Comment puis-je savoir pourquoi son statut est suspendu ?
Ce processus est un lourd INSERT
basé sur une requête coûteuse.Un gros SELECT
qui récupère les données de plusieurs tables et écrit environ 3 à 4 millions de lignes dans une table différente.
Il n'y a pas de verrous/blocs.
Le waittype
il est lié à est CXPACKET
.ce que je peux comprendre car il y a 9 78 comme vous pouvez le voir sur la photo ci-dessous.
Ce qui m'inquiète et ce que j'aimerais vraiment savoir, c'est pourquoi le numéro 1 du SPID
78 est suspendu.
Je comprends que lorsque le statut d'un SPID
est suspendu, cela signifie que le processus attend une ressource et qu'il reprendra lorsqu'il obtiendra sa ressource.
Comment puis-je trouver plus de détails à ce sujet ?quelle ressource ?pourquoi n'est-il pas disponible ?
J'utilise beaucoup le code ci-dessous et ses variantes, mais puis-je faire autre chose pour découvrir pourquoi le SPID
est suspendue?
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
j'ai déjà utilisé sp_whoisactive.Le résultat que j'obtiens pour ce spid78 particulier est le suivant :(divisé en 3 photos pour s'adapter à l'écran)
La solution
SUSPENDU:Cela signifie que la requête n'est actuellement pas active car elle attend une ressource.La ressource peut être une E/S pour lire une page, une WAIT, une communication sur le réseau, ou elle attend un verrou ou un loquet.Il deviendra actif une fois la tâche qu’il attend terminée.Par exemple, si la requête a publié une demande d'E/S pour lire les données d'une table complète tblStudents, cette tâche sera suspendue jusqu'à ce que l'E/S soit terminée.Une fois les E/S terminées (les données de la table tblStudents sont disponibles dans la mémoire), la requête sera déplacée vers la file d'attente RUNNABLE.
Donc, s'il attend, vérifiez la colonne wait_type pour comprendre ce qu'il attend et dépannez en fonction du wait_time.
J'ai développé la procédure suivante qui m'aide, elle inclut le 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
Cette requête ci-dessous peut également afficher des informations de base pour vous aider lorsque le spid est suspendu, en indiquant la ressource que le spid attend.
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
Veuillez voir l'image ci-dessous à titre d'exemple :
Autres conseils
J'utilise sp_whoIsActive pour examiner ce type d'informations car il s'agit d'un outil gratuit prêt à l'emploi qui vous donne de bonnes informations pour dépanner les requêtes lentes :
Comment utiliser sp_WhoIsActive pour rechercher des requêtes SQL Server lentes
Avec cela, vous pouvez obtenir le texte de la requête, le plan qu'elle utilise, la ressource sur laquelle la requête attend, ce qui la bloque, quels verrous elle supprime et bien plus encore.
Beaucoup plus facile que d'essayer de rouler le vôtre.
Vous pouvez le résoudre de plusieurs manières :
- Corrigez l'index du cluster.
- Utilisez des tables temporelles pour obtenir une partie de la table all et travailler avec elle.
J'ai le même problème avec une table avec 400 000 000 de lignes, et j'utilise des tables temporelles pour en obtenir une partie, puis j'utilise mes filtres et mes internes car changer l'index n'était pas une option.
Quelques exemple :
--
--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