web-dev-qa-db-fra.com

Processus de blocage vide dans le rapport de processus bloqué

Je collecte des rapports de processus bloqués à l'aide des événements étendus et, pour une raison quelconque, dans certains rapports, le blocking-process le noeud est vide. Voici le xml complet:

<blocked-process-report monitorLoop="383674">
 <blocked-process>
  <process id="processa7bd5b868" taskpriority="0" logused="106108620" waitresource="KEY: 6:72057613454278656 (8a2f7bc2cd41)" waittime="25343" ownerId="1051989016" transactionname="user_transaction" lasttranstarted="2017-03-20T09:30:38.657" XDES="0x21f382d9c8" lockMode="X" schedulerid="7" kpid="15316" status="suspended" spid="252" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-03-20T09:39:15.853" lastbatchcompleted="2017-03-20T09:39:15.850" lastattention="1900-01-01T00:00:00.850" clientapp="Microsoft Dynamics AX" hostname="***" hostpid="1348" loginname="***" isolationlevel="read committed (2)" xactid="1051989016" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame line="1" stmtstart="40" sqlhandle="0x02000000f7def225b0edaecd8744b453ce09bdcff9b291f50000000000000000000000000000000000000000" />
    <frame line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" />
   </executionStack>
   <inputbuf>
(@P1 bigint,@P2 int)DELETE FROM DIMENSIONFOCUSUNPROCESSEDTRANSACTIONS WHERE ((PARTITION=5637144576) AND ((FOCUSDIMENSIONHIERARCHY=@P1) AND (STATE=@P2)))   </inputbuf>
  </process>
 </blocked-process>
 <blocking-process>
  <process />
 </blocking-process>
</blocked-process-report>

La définition d'index pour l'index auquel appartient hobt_id est

CREATE UNIQUE CLUSTERED INDEX [I_7402FOCUSDIMENSIONHIERARCHYIDX] ON [dbo].[DIMENSIONFOCUSUNPROCESSEDTRANSACTIONS]
(
    [PARTITION] ASC,
    [FOCUSDIMENSIONHIERARCHY] ASC,
    [STATE] ASC,
    [GENERALJOURNALENTRY] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Il n'y a pas de partitionnement impliqué, voici la définition de la table:

CREATE TABLE [dbo].[DIMENSIONFOCUSUNPROCESSEDTRANSACTIONS](
    [FOCUSDIMENSIONHIERARCHY] [bigint] NOT NULL DEFAULT ((0)),
    [GENERALJOURNALENTRY] [bigint] NOT NULL DEFAULT ((0)),
    [STATE] [int] NOT NULL DEFAULT ((0)),
    [RECVERSION] [int] NOT NULL DEFAULT ((1)),
    [PARTITION] [bigint] NOT NULL DEFAULT ((5637144576.)),
    [RECID] [bigint] NOT NULL,
 CONSTRAINT [I_7402RECID] PRIMARY KEY NONCLUSTERED 
(
    [RECID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[DIMENSIONFOCUSUNPROCESSEDTRANSACTIONS]  WITH CHECK ADD CHECK  (([RECID]<>(0)))
GO

Aucun déclencheur ou clé étrangère n'est défini sur aucune des tables de la base de données entière.

La version exacte de SQL Server est:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
23 juin 2016 17:45:11 Copyright (c) Microsoft Corporation Enterprise Edition: Licence basée sur le noyau (64 bits) sur Windows NT 6.3 (Build 14393:) (Hyperviseur)

Les événements étendus sont assez simples, il suffit de consigner les rapports de processus bloqués:

CREATE EVENT SESSION [Dynperf_Blocking_Data] ON SERVER 
ADD EVENT sqlserver.blocked_process_report(
    ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)),
ADD EVENT sqlserver.lock_escalation(
    ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)),
ADD EVENT sqlserver.xml_deadlock_report(
    ACTION(package0.collect_system_time,sqlserver.client_hostname,sqlserver.context_info)) 
ADD TARGET package0.event_file(SET filename=N'F:\SQLTrace\Dynamics_Blocking.xel',max_file_size=(100),max_rollover_files=(10))
WITH (MAX_MEMORY=32768 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=PER_NODE,TRACK_CAUSALITY=ON,STARTUP_STATE=ON)
GO

La base de données est configurée dans Read Committed Snapshot Isolation et le degré maximal de parallélisme est défini sur 1. Voici la configuration du serveur:

+------------------------------------+-------+
|                name                | value |
+------------------------------------+-------+
| access check cache bucket count    |     0 |
| access check cache quota           |     0 |
| Ad Hoc Distributed Queries         |     0 |
| affinity I/O mask                  |     0 |
| affinity mask                      |     0 |
| affinity64 I/O mask                |     0 |
| affinity64 mask                    |     0 |
| Agent XPs                          |     1 |
| allow updates                      |     0 |
| backup compression default         |     1 |
| blocked process threshold (s)      |     2 |
| c2 audit mode                      |     0 |
| clr enabled                        |     0 |
| common criteria compliance enabled |     0 |
| contained database authentication  |     0 |
| cost threshold for parallelism     |     5 |
| cross db ownership chaining        |     0 |
| cursor threshold                   |    -1 |
| Database Mail XPs                  |     1 |
| default full-text language         |  1033 |
| default language                   |     0 |
| default trace enabled              |     1 |
| disallow results from triggers     |     0 |
| EKM provider enabled               |     0 |
| filestream access level            |     0 |
| fill factor (%)                    |     0 |
| ft crawl bandwidth (max)           |   100 |
| ft crawl bandwidth (min)           |     0 |
| ft notify bandwidth (max)          |   100 |
| ft notify bandwidth (min)          |     0 |
| index create memory (KB)           |     0 |
| in-doubt xact resolution           |     0 |
| lightweight pooling                |     0 |
| locks                              |     0 |
| max degree of parallelism          |     1 |
| max full-text crawl range          |     4 |
| max server memory (MB)             | 65536 |
| max text repl size (B)             | 65536 |
| max worker threads                 |     0 |
| media retention                    |     0 |
| min memory per query (KB)          |  1024 |
| min server memory (MB)             |     0 |
| nested triggers                    |     1 |
| network packet size (B)            |  4096 |
| Ole Automation Procedures          |     0 |
| open objects                       |     0 |
| optimize for ad hoc workloads      |     1 |
| PH timeout (s)                     |    60 |
| precompute rank                    |     0 |
| priority boost                     |     0 |
| query governor cost limit          |     0 |
| query wait (s)                     |    -1 |
| recovery interval (min)            |     0 |
| remote access                      |     1 |
| remote admin connections           |     0 |
| remote login timeout (s)           |    10 |
| remote proc trans                  |     0 |
| remote query timeout (s)           |   600 |
| Replication XPs                    |     0 |
| scan for startup procs             |     1 |
| server trigger recursion           |     1 |
| set working set size               |     0 |
| show advanced options              |     1 |
| SMO and DMO XPs                    |     1 |
| transform noise words              |     0 |
| two digit year cutoff              |  2049 |
| user connections                   |     0 |
| user options                       |     0 |
| xp_cmdshell                        |     0 |
+------------------------------------+-------+

J'ai exécuté une trace côté serveur pendant un certain temps et j'obtiens les mêmes nœuds vides dans un fichier de trace que j'utilise des événements étendus.
Ce rapport de processus bloqué a été capturé à l'aide d'une trace côté serveur sur un autre serveur exécutant également Dynamics AX, il n'est donc pas spécifique à ce serveur ou à cette version.

<blocked-process-report monitorLoop="1327922">
 <blocked-process>
  <process id="processbd9839848" taskpriority="0" logused="1044668" waitresource="KEY: 5:72057597098328064 (1d7966fe609a)" waittime="316928" ownerId="3415555263" transactionname="user_transaction" lasttranstarted="2017-03-27T07:59:29.290" XDES="0x1c1c0c3b0" lockMode="U" schedulerid="3" kpid="25236" status="suspended" spid="165" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-03-27T07:59:47.873" lastbatchcompleted="2017-03-27T07:59:47.873" lastattention="2017-03-27T07:58:01.490" clientapp="Microsoft Dynamics AX" hostname="***" hostpid="11072" loginname="***" isolationlevel="read committed (2)" xactid="3415555263" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame line="1" stmtstart="236" stmtend="676" sqlhandle="0x020000004d6830193d42a167edd195c201f40bb772e9ece20000000000000000000000000000000000000000"/>
   </executionStack>
   <inputbuf>
(@P1 numeric(32,16),@P2 int,@P3 bigint,@P4 nvarchar(5),@P5 nvarchar(36),@P6 int,@P7 numeric(32,16),@P8 bigint,@P9 int)UPDATE PRODCALCTRANS SET REALCOSTAMOUNT=@P1,RECVERSION=@P2 WHERE (((((((PARTITION=@P3) AND (DATAAREAID=@P4)) AND (COLLECTREFPRODID=@P5)) AND (COLLECTREFLEVEL=@P6)) AND (LINENUM=@P7)) AND (RECID=@P8)) AND (RECVERSION=@P9))   </inputbuf>
  </process>
 </blocked-process>
 <blocking-process>
  <process/>
 </blocking-process>
</blocked-process-report>

Quelqu'un at-il une explication à ces rapports? Qu'est-ce qui bloque la requête?

Existe-t-il un moyen de savoir ce qui se passait si je regarde les rapports après que les verrous ont disparu depuis longtemps?

Une chose qui pourrait être utile d'ajouter est que ces requêtes sont exécutées via sp_cursorprepareet sp_cursorexecute

Jusqu'à présent, je n'ai pas pu le reproduire, cela semble arriver au hasard mais très souvent.

Cela se produit sur plusieurs instances (de versions différentes) et plusieurs tables/requêtes, toutes liées à Dynamics AX.

Il n'y a aucun travail de maintenance d'index ou de base de données survenant en arrière-plan à ce moment.

En utilisant le code fourni dans le réponse de srutzky j'ai pu capturer une journalisation liée à ce rapport de processus bloqué:

<blocked-process-report monitorLoop="1621637">
 <blocked-process>
  <process id="processd06909c28" taskpriority="0" logused="0" waitresource="KEY: 5:72057597585719296 (d2d87c26d920)" waittime="78785" ownerId="4436575948" transactionname="user_transaction" lasttranstarted="2017-04-13T07:39:17.590" XDES="0x3219d034e0" lockMode="U" schedulerid="3" kpid="133792" status="suspended" spid="106" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-04-13T07:39:17.657" lastbatchcompleted="2017-04-13T07:39:17.657" lastattention="1900-01-01T00:00:00.657" clientapp="Microsoft Dynamics AX" hostname="****" hostpid="11800" loginname="****" isolationlevel="read committed (2)" xactid="4436575948" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame line="1" stmtstart="72" stmtend="256" sqlhandle="0x0200000076a6a92ab1256af09321b056ab243f187342f9960000000000000000000000000000000000000000"/>
    <frame line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"/>
   </executionStack>
   <inputbuf>
(@P1 int,@P2 int,@P3 bigint,@P4 int)UPDATE PRODROUTEJOB SET JOBSTATUS=@P1,RECVERSION=@P2 WHERE ((RECID=@P3) AND (RECVERSION=@P4))   </inputbuf>
  </process>
 </blocked-process>
 <blocking-process>
  <process/>
 </blocking-process>
</blocked-process-report>

Cela se trouve dans les tables de journalisation pour la même ressource à cette époque: Gist en raison de la limite de caractères

Une enquête plus approfondie montre que juste avant et après le rapport avec un processus de blocage vide, j'ai des rapports pour le même ID de ressource qui ont des nœuds de processus de blocage:

<blocked-process-report monitorLoop="1621636">
 <blocked-process>
  <process id="processd06909c28" taskpriority="0" logused="0" waitresource="KEY: 5:72057597585719296 (d2d87c26d920)" waittime="73765" ownerId="4436575948" transactionname="user_transaction" lasttranstarted="2017-04-13T07:39:17.590" XDES="0x3219d034e0" lockMode="U" schedulerid="3" kpid="133792" status="suspended" spid="106" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-04-13T07:39:17.657" lastbatchcompleted="2017-04-13T07:39:17.657" lastattention="1900-01-01T00:00:00.657" clientapp="Microsoft Dynamics AX" hostname="***" hostpid="11800" loginname="***" isolationlevel="read committed (2)" xactid="4436575948" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack>
    <frame line="1" stmtstart="72" stmtend="256" sqlhandle="0x0200000076a6a92ab1256af09321b056ab243f187342f9960000000000000000000000000000000000000000"/>
    <frame line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"/>
   </executionStack>
   <inputbuf>
(@P1 int,@P2 int,@P3 bigint,@P4 int)UPDATE PRODROUTEJOB SET JOBSTATUS=@P1,RECVERSION=@P2 WHERE ((RECID=@P3) AND (RECVERSION=@P4))   </inputbuf>
  </process>
 </blocked-process>
 <blocking-process>
  <process status="sleeping" spid="105" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2017-04-13T07:40:31.417" lastbatchcompleted="2017-04-13T07:40:31.423" lastattention="1900-01-01T00:00:00.423" clientapp="Microsoft Dynamics AX" hostname="**" hostpid="11800" loginname="**" isolationlevel="read committed (2)" xactid="4436165115" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
   <executionStack/>
   <inputbuf>
(@P1 bigint,@P2 nvarchar(5),@P3 bigint,@P4 bigint,@P5 nvarchar(11),@P6 int,@P7 nvarchar(21),@P8 datetime2)SELECT T1.REGDATETIME,T1.REGDATETIMETZID,T1.WORKERPILOT,T1.WORKER,T1.WRKCTRIDPILOT,T1.REGTYPE,T1.PROFILEDATE,T1.JOBID,T1.JOBIDABS,T1.MATCHRECIDSTARTSTOP,T1.JOBACTIVE,T1.RESNO,T1.STARTITEMS,T1.GOODITEMS,T1.SCRAPITEMS,T1.FINISHEDCODE,T1.TMPGOODITEMS,T1.TMPSCRAPITEMS,T1.SYSMRPUPDATEREQUEST,T1.ERROR,T1.ERRORTXT,T1.TMPSTARTITEMS,T1.AUTOSTAMP,T1.ERRORSPECIFICATION,T1.COSTCATEGORY,T1.ONCALLACTIVITY,T1.TERMINALID,T1.PDSCWGOODITEMS,T1.PDSCWSCRAPITEMS,T1.PDSCWSTARTITEMS,T1.RETAILTERMINALID,T1.MODIFIEDDATETIME,T1.RECVERSION,T1.PARTITION,T1.RECID FROM JMGTERMREG T1 WHERE (((PARTITION=@P1) AND (DATAAREAID=@P2)) AND (((((WORKER=@P3) OR ((WORKER=@P4) AND (WRKCTRIDPILOT=@P5))) AND (REGTYPE=@P6)) AND (JOBID=@P7)) AND (REGDATETIME&gt;=@P8))) ORDER BY T1.REGDATETIME   </inputbuf>
  </process>
 </blocking-process>
</blocked-process-report>

En utilisant le nouveau script fourni par srutzky de nouvelles données ont été collectées. Il est publié sur github en raison de la longueur maximale du message.

Étant donné que les données initialement publiées n'avaient pas les deux identifiants de session, de nouvelles données ont été publiées sur github à nouvea

Nouvelles données, y compris les connexions sur github

Je ne peux pas tester cette théorie pour le moment, mais sur la base des données de capture les plus récentes publiées sur GitHub , je dirais que la raison pour laquelle vous <process> le noeud est vide, c'est qu'il nécessite une requête en cours d'exécution (de nombreux attributs se trouvent dans sys.dm_exec_requests et pas dans sys.dm_exec_sessions) et sans demande en cours d'exécution, il ne peut pas rapporter de détails, semblable à la façon de faire un INNER JOIN entre sys.dm_exec_requests et sys.dm_exec_sessions exclura les lignes où une session est active mais inactive car aucune demande n'est en cours.

En regardant l'ensemble supérieur de données (monitorLoop valeurs: 1748823, 1748824, 1748825 et 1748827), nous pouvons voir ce qui suit:

  • le id du blocked-process est le même dans chaque cas: process2552c1fc28 , et le seul attribut différent est le waittime (compréhensible).
  • les attributs du blocking-process les nœuds présentent des différences entre lastbatchstarted et lastbatchcompleted
  • les attributs du blocking-process les nœuds affichent des valeurs identiques pour spid et xactid

Alors, comment les SessionID et TransactionID du processus de blocage peuvent-ils être les mêmes sur 4 lots de requêtes différents? Facile, une transaction explicite a été lancée puis ces lots ont été exécutés. Et comme ce sont des lots séparés, il y a du temps entre leur soumission, auquel cas il n'y a pas de demande en cours, donc aucune information de processus à afficher (mais la session et la transaction sont toujours là).

Afin d'effectuer des recherches supplémentaires à ce sujet, vous pouvez capturer des informations utiles à partir de sys.dm_exec_requests et sys.dm_tran_locks en plaçant le T-SQL suivant dans une étape de travail de l'Agent SQL Server "Script Transaction-SQL (T-SQL)", en définissant la "Base de données" comme étant celle que vous recherchez (dans ce cas, c'est celle avec un ID de 6) et planifier l'exécution de ce travail toutes les 10 secondes. Le T-SQL ci-dessous créera les deux tables dans cette même base de données si elles n'existent pas, puis remplira la table "Requêtes" si une requête se bloque elle-même ou si c'est une opération de suppression ou de mise à jour qui est bloquée . Si des demandes sont trouvées, il tentera de capturer:

  • Session et demande d'informations sur le processus de blocage (cette partie ne suppose pas qu'il existe une demande active, d'où le RIGHT JOIN pour au moins obtenir les informations de session)
  • Informations de connexion pour les processus bloqués et (espérons-le) bloquants.
  • les verrous actuels pour ces mêmes id_session (gardez à l'esprit que les informations de verrouillage ne sont pas garanties pour être exactes à 100% car ces informations peuvent changer dans le temps entre l'exécution de ces deux instructions; quand même, les informations sont assez bonnes assez souvent pour mériter d'être capturées). Cette section est actuellement commentée.

Étape du travail T-SQL de l'Agent SQL Server:

-- !! Remember to set the "Database" for the T-SQL Job Step to
--    the DB that has database_id = 6 !!
SET NOCOUNT ON;
IF (OBJECT_ID(N'dbo.tmpBlockingResearch_Requests') IS NULL)
BEGIN
  -- Create requests capture table
  SELECT SYSDATETIME() AS [CaptureTime], req.*,
         ses.login_time, ses.[Host_name], ses.[program_name], ses.Host_process_id,
         ses.client_version, ses.client_interface_name, ses.security_id,
         ses.login_name, ses.nt_domain, ses.nt_user_name, ses.memory_usage,
         ses.total_scheduled_time, ses.endpoint_id, ses.last_request_start_time,
         ses.last_request_end_time, ses.is_user_process, ses.original_security_id,
         ses.original_login_name, ses.last_successful_logon, ses.last_unsuccessful_logon,
         ses.unsuccessful_logons, ses.authenticating_database_id
  INTO   dbo.tmpBlockingResearch_Requests
  FROM   sys.dm_exec_requests req
  INNER JOIN sys.dm_exec_sessions ses
          ON ses.[session_id] = req.[session_id]
  WHERE  1 = 0;
END;

IF (OBJECT_ID(N'dbo.tmpBlockingResearch_Connections') IS NULL)
BEGIN
  -- Create connections capture table
  SELECT SYSDATETIME() AS [CaptureTime], con.*
  INTO   dbo.tmpBlockingResearch_Connections
  FROM   sys.dm_exec_connections con
  WHERE  1 = 0;
END;

IF (OBJECT_ID(N'dbo.tmpBlockingResearch_Locks') IS NULL)
BEGIN
  -- Create locks capture table
  SELECT SYSDATETIME() AS [CaptureTime], loc.*
  INTO   dbo.tmpBlockingResearch_Locks
  FROM   sys.dm_tran_locks loc
  WHERE  1 = 0;
END;
---------------------------------
DECLARE @SessionIDs TABLE (SessionID SMALLINT NOT NULL,
                           BlockingSessionID SMALLINT NOT NULL);

INSERT INTO dbo.tmpBlockingResearch_Requests
OUTPUT inserted.[session_id], inserted.[blocking_session_id]
INTO   @SessionIDs ([SessionID], [BlockingSessionID])
  SELECT SYSDATETIME() AS [CaptureTime], req.*,
         ses.login_time, ses.[Host_name], ses.[program_name], ses.Host_process_id,
         ses.client_version, ses.client_interface_name, ses.security_id,
         ses.login_name, ses.nt_domain, ses.nt_user_name, ses.memory_usage,
         ses.total_scheduled_time, ses.endpoint_id, ses.last_request_start_time,
         ses.last_request_end_time, ses.is_user_process, ses.original_security_id,
         ses.original_login_name, ses.last_successful_logon, ses.last_unsuccessful_logon,
         ses.unsuccessful_logons, ses.authenticating_database_id
  FROM   sys.dm_exec_requests req
  INNER JOIN sys.dm_exec_sessions ses
          ON ses.[session_id] = req.[session_id]
  WHERE ses.[is_user_process] = 1
  AND   req.[database_id] = DB_ID()
  AND   (
          req.blocking_session_id IN (req.[session_id], -2, -3, -4)
    OR   (req.[command] IN (N'DELETE', N'UPDATE') AND req.[blocking_session_id] > 0)
        );

-- Get at least session info, if not also request info, on blocking process
INSERT INTO dbo.tmpBlockingResearch_Requests
  SELECT SYSDATETIME() AS [CaptureTime], req.*,
         ses.login_time, ses.[Host_name], ses.[program_name], ses.Host_process_id,
         ses.client_version, ses.client_interface_name, ses.security_id,
         ses.login_name, ses.nt_domain, ses.nt_user_name, ses.memory_usage,
         ses.total_scheduled_time, ses.endpoint_id, ses.last_request_start_time,
         ses.last_request_end_time, ses.is_user_process, ses.original_security_id,
         ses.original_login_name, ses.last_successful_logon, ses.last_unsuccessful_logon,
         ses.unsuccessful_logons, ses.authenticating_database_id
  FROM   sys.dm_exec_requests req
  RIGHT JOIN sys.dm_exec_sessions ses
          ON ses.[session_id] = req.[session_id]
  WHERE ses.[session_id] IN (SELECT DISTINCT [BlockingSessionID] FROM @SessionIDs);

-- If any rows are captured this time, try to capture their connection info
INSERT INTO dbo.tmpBlockingResearch_Connections
  SELECT SYSDATETIME() AS [CaptureTime], con.*
  FROM   sys.dm_exec_connections con
  WHERE  con.[session_id] IN (
                              SELECT [SessionID]
                              FROM @SessionIDs
                              UNION -- No "ALL" so it does DISTINCT
                              SELECT [BlockingSessionID]
                              FROM @SessionIDs
                             );

/*
-- If any rows are captured this time, try to capture their lock info
INSERT INTO dbo.tmpBlockingResearch_Locks
  SELECT SYSDATETIME() AS [CaptureTime], loc.*
  FROM   sys.dm_tran_locks loc
  WHERE  loc.[request_session_id] IN (
                                      SELECT [SessionID]
                                      FROM @SessionIDs
                                      UNION -- No "ALL" so it does DISTINCT
                                      SELECT [BlockingSessionID]
                                      FROM @SessionIDs
                                     );
 */

Je pense que vous devriez pouvoir reproduire cela en ouvrant un onglet de requête et en exécutant ce qui suit:

CREATE TABLE dbo.tmp (Col1 INT);
BEGIN TRAN;
INSERT INTO dbo.tmp (Col1) VALUES (1);

Ensuite, ouvrez un deuxième onglet de requête et exécutez ce qui suit:

UPDATE dbo.tmp
SET    Col1 = 2
WHERE  Col1 = 1;

P.S. Juste pour l'avoir dit, la seule chose qui n'a pas de sens est que les informations de demande et de session - dbo.tmpBlockingResearch_Requests - ne contient toujours pas de lignes pour la session de blocage. Pourtant, je sais que la variable de table contient l'ID de session de blocage, car elle a tiré les verrous pour les deux SessionID. Cela pourrait indiquer un scénario dans lequel une transaction est autorisée à rester ouverte après la fermeture de la "connexion" du client, mais la connexion est toujours maintenue en raison du pool de connexions.

6
Solomon Rutzky

Des transactions bloquées peuvent se produire en raison des escalades de verrous.

Ceci est expliqué dans l'article du support Microsoft:

Comment résoudre les problèmes de blocage causés par l'escalade de verrous dans SQL Server

...
L'escalade de verrous ne provoque pas la plupart des problèmes de blocage. Pour déterminer si l'escalade de verrous se produit à peu près au moment où vous rencontrez des problèmes de blocage, démarrez une trace du Générateur de profils SQL qui inclut l'événement Lock: Escalation. Si vous ne voyez aucun événement Lock: Escalation, l'escalade de verrous ne se produit pas sur votre serveur et les informations contenues dans cet article ne s'appliquent pas à votre situation.

Si une escalade de verrous se produit, vérifiez que le verrou de table escaladé bloque d'autres utilisateurs
...

Vérifiez les événements étendus (fichier physique) pour les événements d'escalade de verrous qui se sont produits avant le processus bloqué événement.

Expliquant

Il y a un article sur le blog Microsoft qui va plus en détail:

Escalade et blocage des verrous SQL Server

...
Étape 2: collecte des escalades de verrous et des événements de rapport de processus bloqués.

Les événements d'escalade de verrous et de rapports de processus bloqués ne sont pas automatiquement capturés par SQL Server. Afin de savoir si ces événements se produisent, nous devons dire à SQL Server de les enregistrer. Notre équipe utilise l'outil Performance Analyzer pour Microsoft Dynamics pour recueillir ces informations. Consultez cet article de Rod Hansen pour plus d'informations sur l'outil et comment collecter les détails de blocage avec lui. Si vous souhaitez simplement utiliser SQL Server Profiler, les événements que vous devez collecter sont indiqués ci-dessous: ...

Après avoir capturé les escalades de verrous et les processus bloqués, vous devez déterminer si les escalades de verrous sont la cause première des processus bloqués:

...
Étape 3: passez en revue la trace dans SQL Server Profiler.

Il existe deux indicateurs principaux qui vous indiqueront si le blocage est lié à l'escalade de verrous.

Tout d'abord, vous voyez une série d'événements d'escalade de verrous précédant immédiatement les événements de rapport de processus bloqués. Voici un exemple tiré d'une trace produite par l'outil Performance Analyzer pour Microsoft Dynamics. C'est une chose à rechercher dans la trace, mais cela ne signifie pas à lui seul que l'escalade de verrous est à l'origine du blocage. ...

et plus loin

Pour vérifier que le blocage est bien lié à l'escalade de verrous, vous devez consulter les détails du rapport de processus bloqué. Dans la section TextData, recherchez waitresource (voir la capture d'écran ci-dessous). Si waitresource commence par OBJECT, nous savons que l'instruction bloquée attend la libération d'un verrou de niveau table avant de pouvoir continuer. Si waitresource commence par [~ # ~] touche [~ # ~] ou [~ # ~] pag [ ~ # ~] au lieu de OBJECT, alors l'escalade de verrous n'est pas impliquée dans ce bloc spécifique . L'escalade de verrous augmentera toujours la portée d'un verrou vers OJBECT, peu importe où il commence

Solution

(uniquement si les correspondances mentionnées ci-dessus)

La solution est apparemment d'activer l'indicateur de trace 1224 qui désactivera l'escalade des verrous:

Escalade et blocage des verrous SQL Server

Si vous voyez ces deux choses ensemble, il y a fort à parier que l'escalade de verrous est à l'origine du blocage et vous bénéficierez probablement de l'implémentation de l'indicateur de trace 1224 de SQL Server.

Indicateurs de trace SQL Server pour Dynamics AX

L'indicateur de trace 1224 désactive l'escalade des verrous en fonction du nombre de verrous. L'activation de cet indicateur de trace peut réduire la probabilité de blocage en raison de l'escalade des verrous, ce que j'ai vu avec un certain nombre d'implémentations AX. Le scénario le plus courant où cela devient un problème est quand il est nécessaire que Master Planning s'exécute pendant la journée

Réponse

En fin de compte, il se pourrait que l'escalade des verrous soit la cause première des processus bloqués.


Solution alternative (nœud de processus vide)

Après une enquête plus approfondie de certains rapports bloqués_processus, l'autre explication suivante peut être faite.

Les événements étendus capturent les rapports bloqués_processus qui ne sont liés à aucun autre processus à l'époque.

Ergo: Ils doivent être bloqués pour une raison différente

Je vous suggère de capturer un laps de temps de types d'attente à partir de la vue sys.dm_os_wait_stats sur votre serveur SQL et de corréler les nombres avec les blocs_process_reports qui se produisent pendant vos mesures. Paul Randall a un bon script: Envoyez-moi vos statistiques d'attente et obtenez mes conseils et 30 jours de Pluralsight gratuits en retour

Le script capture les compteurs actuels, attend 23 heures (peut être modifié), recapture à nouveau les compteurs actuels et les compare pour vous donner les 95% de types d'attente les plus fréquents. Vous pouvez l'essayer pendant une heure, disons, et avoir le fichier XEL à portée de main.

Vous pouvez trouver un type d'attente (par exemple LCK_M_SH,…) qui vous indique que votre stockage est lent à écrire. Ou que vous avez d'autres frais généraux (par exemple CX_PACKET_WAITS,….). Quelque chose ralentit vos mises à jour. Vous pouvez ensuite voir si les sys.dm_os_wait_stats se rapportent aux blocs_process_reports avec les nœuds vides.

Il y a des cas où un SPID bloqué est bloqué par le même SPID:

La colonne bloquée dans la table sysprocesses est remplie pour les attentes de verrouillage après avoir installé SQL Server 2000 SP4

Lorsqu'un SPID attend un verrouillage de page d'E/S, vous pouvez remarquer que la colonne bloquée signale brièvement que le SPID se bloque. Ce comportement est un effet secondaire de la façon dont les verrous sont utilisés pour les opérations d'E/S sur les pages de données. Lorsqu'un thread émet une demande d'E/S, le SPID qui émet la demande d'E/S acquiert un verrou sur la page. Toutes les opérations d'E/S SQL Server 2000 sont asynchrones. Par conséquent, le SPID tentera d'acquérir un autre verrou sur la même page si le SPID qui a émis la demande d'E/S doit attendre la fin de la demande. Ce deuxième verrou est bloqué par le premier verrou. Par conséquent, la colonne bloquée signale que le SPID se bloque. Une fois la demande d'E/S terminée, le premier verrou est libéré. Ensuite, la deuxième demande de verrouillage est accordée.

Autre réponse

Ceci est une indication supplémentaire que vous pouvez rencontrer des problèmes IO. Ces problèmes entraînent des "processus bloqués" mais sans SPID étranger associé. Les événements étendus peuvent ne pas signaler le processus/SPID dans un nœud distinct .

4
John aka hot2use