Proceso de bloqueo vacío en informe de proceso bloqueado


28

Estoy recopilando informes de procesos bloqueados usando Eventos extendidos y, por alguna razón, en algunos informes el blocking-processnodo está vacío. Este es el xml completo:

<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 definición de índice para el índice al que pertenece hobt_id es

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

No hay particiones involucradas, esta es la definición de la tabla:

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

No hay activadores o claves foráneas definidas en ninguna de las tablas en toda la base de datos.

La compilación exacta de SQL Server es:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
23 de junio de 2016 17:45:11 Copyright (c) Microsoft Corporation Enterprise Edition: Licencias basadas en Core (64 bits) en Windows NT 6.3 ( Compilación 14393:) (hipervisor)

Los eventos extendidos son bastante simples, solo registran los informes de procesos bloqueados:

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 datos se configura en Aislamiento de instantáneas de lectura confirmada y el grado máximo de paralelismo se establece en 1. Esta es la configuración del servidor:

+------------------------------------+-------+
|                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 |
+------------------------------------+-------+

Ejecuté una traza del lado del servidor durante un tiempo y obtengo los mismos nodos vacíos en un archivo de traza que con los eventos extendidos.
Este informe de proceso bloqueado se capturó utilizando un rastreo del lado del servidor en otro servidor que también ejecuta Dynamics AX, por lo que no es específico de este servidor o compilación.

<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>

¿Alguien tiene una explicación para estos informes? ¿Qué está bloqueando la consulta?

¿Hay alguna manera de averiguar qué estaba sucediendo si estoy mirando los informes después de que las cerraduras se hayan ido hace mucho tiempo?

Una cosa que podría ser útil agregar es que estas consultas se ejecutan a través de sp_cursorprepareysp_cursorexecute

Hasta ahora no he podido reproducirlo, parece suceder al azar pero muy a menudo.

Ocurre en varias instancias (de diferentes compilaciones) y varias tablas / consultas, todas relacionadas con Dynamics AX.

No hay trabajos de mantenimiento de índice u otras bases de datos que se realicen en segundo plano en ese momento.

Usando el código provisto en la respuesta de srutzky pude capturar algunos registros relacionados con este informe de proceso bloqueado:

<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>

Esto se encuentra en las tablas de registro para el mismo recurso en ese momento: Gist debido al límite de caracteres

La investigación adicional muestra que justo antes y después del informe con un proceso de bloqueo vacío, tengo informes para el mismo recurso que tienen nodos de proceso de bloqueo:

<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>

Usando el nuevo script proporcionado por srutzky , se han recopilado nuevos datos. Está publicado en github debido a la longitud máxima de publicación.

Dado que los datos publicados originalmente no tenían ambos identificadores de sesión, algunos datos nuevos se han publicado nuevamente en github

Nuevos datos, incluidas las conexiones en github

Respuestas:


6

No puedo probar esta teoría en este momento, pero según los datos de captura más recientes publicados en GitHub , diría que la razón por la que el <process>nodo está vacío es que requiere una solicitud actualmente en ejecución (muchos de los atributos se encuentran en sys.dm_exec_requestsy no en sys.dm_exec_sessions) y sin una solicitud actualmente en ejecución, no puede informar ningún detalle, similar a cómo hacer un INNER JOINintermedio sys.dm_exec_requestsy sys.dm_exec_sessionsexcluirá las filas donde una sesión está activa pero está inactiva debido a que no hay una solicitud actual.

Mirando el conjunto superior de datos ( monitorLoopvalores: 1748823, 1748824, 1748825 y 1748827) podemos ver lo siguiente:

  • el idde the blocked-processes el mismo en cada caso: process2552c1fc28 , y el único atributo que es diferente es el waittime(comprensiblemente).
  • los atributos de los blocking-processnodos muestran diferencias en ambos lastbatchstartedylastbatchcompleted
  • los atributos de los blocking-processnodos muestran valores idénticos para spidyxactid

Entonces, ¿cómo pueden ser iguales el SessionID y el TransactionID del proceso de bloqueo en 4 lotes de consultas diferentes? Fácil, se inició una transacción explícita y luego se ejecutaron estos lotes. Y debido a que estos son lotes separados, hay un tiempo entre ellos que se envían, en ese momento no hay una solicitud actual, por lo tanto, no hay información de proceso para mostrar (pero la sesión y la transacción todavía están allí).

Para realizar una investigación adicional sobre esto, puede capturar información útil de sys.dm_exec_requestsy sys.dm_tran_lockscolocando el siguiente T-SQL en un paso de trabajo "Transaction-SQL script (T-SQL)" del Agente SQL Server, configurando la "Base de datos" como el uno que está investigando (en este caso, es el que tiene un ID de 6) y programa este trabajo para que se ejecute cada 10 segundos. El T-SQL a continuación creará las dos tablas en esa misma base de datos si no existen y luego completará la tabla "Solicitudes" si alguna solicitud se está bloqueando a sí misma, o si se está bloqueando una operación de Eliminar o Actualizar . Si se encuentran solicitudes, intentará capturar:

  • Información de sesión y solicitud sobre el proceso de bloqueo (esta parte no supone que haya una solicitud activa, por lo tanto, RIGHT JOINpara obtener al menos la información de la sesión)
  • Información de conexión para los procesos bloqueados y (con suerte) de bloqueo.
  • los bloqueos actuales para esos mismos session_id's (solo tenga en cuenta que no se garantiza que la información de bloqueo sea ​​100% precisa ya que esa información puede cambiar en el tiempo entre la ejecución de esas dos declaraciones; aún así, la información es lo suficientemente buena como para ser vale la pena capturar). Esta sección está actualmente comentada.

Paso del trabajo de SQL Server Agent T-SQL:

-- !! 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
                                     );
 */

Creo que debería poder reproducir esto abriendo una pestaña de consulta y ejecutando lo siguiente:

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

Luego, abra una segunda pestaña de consulta y ejecute lo siguiente:

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

PD: Solo para decirlo, lo único que no tiene sentido es que la información de la solicitud y la sesión dbo.tmpBlockingResearch_Requests, todavía no contiene filas para la sesión de bloqueo. Sin embargo, sé que la variable de la tabla tiene la identificación de la sesión de bloqueo, ya que atrapó los bloqueos para ambos SessionID. Esto podría apuntar a un escenario en el que se permite que una Transacción permanezca abierta después de que se cierra la "conexión" del cliente pero la conexión aún se mantiene debido a la Agrupación de conexiones.


@ TomV He revisado los datos de investigación más recientes y tengo una teoría bastante sólida. He actualizado mi respuesta en consecuencia, incluida la adición de una sección a mis consultas de investigación, así que reemplace el paso de trabajo SQL con las nuevas consultas aquí (también comenté la consulta de "bloqueos", ya que realmente no necesitamos esos datos en este momento y son muchos datos) Sugiero truncar / soltar las tablas de investigación existentes para comenzar desde cero.
Solomon Rutzky

@TomV Ok. Y he actualizado mi consulta de repro para que sea una ACTUALIZACIÓN en lugar de una SELECCIÓN, por lo que de todos modos debería ser más representativa de su situación. También agregué una nota al final sobre las filas que faltan en la tabla de solicitudes. Esperemos que la nueva tabla de Conexiones al menos confirme la existencia continua del SessionID de bloqueo. (PD, comencé a limpiar mis comentarios anteriores).
Solomon Rutzky

Tu trabajo está activo. Tendré que encontrar algo de tiempo para probar el repro y analizarlo la próxima semana
Tom V - Team Monica

Hola solomon Se han publicado 2 nuevos ejemplos en github. Desafortunadamente no pude desencadenar un proceso de bloqueo vacío BPR utilizando el caso de repro que se proporciona.
Tom V - Equipo Mónica

Eché un vistazo muy rápido ya que no tengo mucho tiempo. Parece que la información de Conexiones muestra que la ID de la sesión de bloqueo sigue activa pero no está en la tabla de sesiones. Puedo probar esto más tarde, pero estoy bastante seguro de que eso indica la agrupación de conexiones (la conexión todavía está allí) y la conexión que se está cerrando entre comandos, pero una transacción está claramente abierta (ya que la transacción_id es siempre la misma que vimos la última vez).
Echaremos

4

Las transacciones bloqueadas pueden ocurrir debido a escaladas de bloqueo.

Esto se explica en el artículo de soporte de Microsoft:

Cómo resolver los problemas de bloqueo causados ​​por la escalada de bloqueo en SQL Server

...
La escalada de bloqueo no causa la mayoría de los problemas de bloqueo. Para determinar si la escalada de bloqueo se produce alrededor del tiempo cuando experimenta problemas de bloqueo, inicie un rastreo de SQL Profiler que incluya el evento Bloqueo: Escalación. Si no ve ningún bloqueo: eventos de escalada, la escalada de bloqueo no está ocurriendo en su servidor y la información en este artículo no se aplica a su situación.

Si se produce una escalada de bloqueo, verifique que el bloqueo de tabla escalado esté bloqueando a otros usuarios
...

Verifique los Eventos extendidos (archivo físico) para ver los eventos de bloqueo de escala que ocurrieron antes del evento de proceso bloqueado .

Explicando

Hay un artículo del Blog de Microsoft que entra en más detalles:

SQL Server Lock Escalation y bloqueo

...
Paso 2: recopilar eventos de bloqueo de escalamiento e informe de proceso bloqueado.

SQL Server no captura automáticamente la escalada de bloqueo y los eventos de informe de proceso bloqueado. Para saber si estos eventos están sucediendo, necesitamos decirle a SQL Server que los registre. Nuestro equipo utiliza la herramienta Analizador de rendimiento para Microsoft Dynamics para recopilar esa información. Consulte esta publicación de Rod Hansen para obtener más información sobre la herramienta y cómo recopilar detalles de bloqueo con ella. Si solo desea utilizar el SQL Server Profiler, los eventos que necesitaría recopilar se muestran a continuación: ...

Después de haber capturado las escaladas de bloqueo y los procesos bloqueados, debe determinar si las escaladas de bloqueo son la causa principal de los procesos bloqueados:

...
Paso 3: Revise el seguimiento en el SQL Server Profiler.

Hay dos indicadores principales que le dirán si el bloqueo está relacionado con la escalada de bloqueo.

Primero, verá una serie de eventos de escalado de bloqueo inmediatamente anteriores a los eventos de informe de proceso bloqueado. A continuación se muestra un ejemplo tomado de una traza producida por la herramienta Analizador de rendimiento para Microsoft Dynamics. Esto es algo que debe buscar en el rastreo, pero esto solo no significa que la escalada de bloqueo esté causando el bloqueo. ...

y además

Para verificar que el bloqueo está relacionado con la escalada de bloqueo, debe mirar los detalles del informe de proceso bloqueado. En la sección TextData, busque waitresource (vea la captura de pantalla a continuación). Si waitresource comienza con OBJECT, sabemos que la declaración bloqueada está esperando que se libere un bloqueo de nivel de tabla antes de que pueda continuar. Si waitresource comienza con KEY o PAG en lugar de OBJECT, la escalada de bloqueo no está involucrada en ese bloque específico . La escalada de bloqueo siempre aumentará el alcance de un bloqueo a OJBECT independientemente de dónde comience

Solución

(solo si los partidos mencionados anteriormente)

Aparentemente, la solución es activar el indicador de rastreo 1224 que desactivará la escalada de bloqueo:

SQL Server Lock Escalation y bloqueo

Si ve estas dos cosas juntas, es una apuesta bastante buena que la escalada de bloqueo está causando el bloqueo y probablemente se beneficiaría de implementar el indicador de seguimiento 1224 de SQL Server.

Indicadores de seguimiento de SQL Server para Dynamics AX

La marca de seguimiento 1224 deshabilita la escalada de bloqueo en función del número de bloqueos. Habilitar este indicador de rastreo puede reducir la probabilidad de bloqueo debido a la escalada de bloqueo, algo que he visto con varias implementaciones de AX. El escenario más común en el que esto se convierte en un problema es cuando hay un requisito para que la Planificación maestra se ejecute durante el día

Responder

Al final, podría ser que la escalada de bloqueo sea la causa raíz de los procesos bloqueados.


Solución alternativa (nodo de proceso vacío)

Después de una investigación adicional de algunos informes de proceso bloqueados, se puede hacer la siguiente explicación alternativa.

Los eventos extendidos capturan informes_proceso_bloqueados que no están relacionados con ningún otro proceso en ese momento.

Ergo: deben ser bloqueados por una razón diferente

Le sugiero que capture un marco de tiempo de tipos de espera desde la vista sys.dm_os_wait_stats en su SQL Server y correlacione los números con los informes de proceso bloqueados que ocurren durante sus mediciones. Paul Randall tiene un buen guión: envíeme sus estadísticas de espera y obtenga mi consejo y 30 días de Pluralsight gratis a cambio

Los scripts capturan los contadores actuales, esperan 23 horas (se pueden modificar), vuelven a capturar los contadores actuales y los comparan para obtener el 95% de los mejores tipos de espera. Puede probar esto durante aproximadamente 1 hora y tener a mano el archivo XEL.

Puede encontrar un tipo de espera (por ejemplo, LCK_M_SH, ...) que le indica que su almacenamiento es lento en la escritura. O que tiene alguna otra sobrecarga (por ejemplo, CX_PACKET_WAITS, ...). Algo está ralentizando sus actualizaciones. A continuación, puede ver si sys.dm_os_wait_stats se relacionan con los bloqueados_procesos_reports con los nodos vacíos.

Hay casos en que un SPID bloqueado está siendo bloqueado por el mismo SPID:

La columna bloqueada en la tabla sysprocesses se rellena para esperas de cierre después de instalar SQL Server 2000 SP4

Cuando un SPID está esperando un bloqueo de página de E / S, puede observar que la columna bloqueada informa brevemente que el SPID se está bloqueando a sí mismo. Este comportamiento es un efecto secundario de la forma en que se utilizan los pestillos para las operaciones de E / S en las páginas de datos. Cuando un hilo emite una solicitud de E / S, el SPID que emite la solicitud de E / S adquiere un bloqueo en la página. Todas las operaciones de E / S de SQL Server 2000 son asíncronas. Por lo tanto, el SPID intentará adquirir otro pestillo en la misma página si el SPID que emitió la solicitud de E / S debe esperar a que finalice la solicitud. Este segundo pestillo está bloqueado por el primer pestillo. Por lo tanto, la columna bloqueada informa que el SPID se está bloqueando a sí mismo. Cuando finaliza la solicitud de E / S, se libera el primer pestillo. Luego, se otorga la segunda solicitud de cierre.

Respuesta alternativa

Esta es una indicación más de que puede tener problemas de E / S. Estos problemas resultan en "procesos bloqueados" pero sin un SPID externo relacionado. Los eventos extendidos podrían no informar el proceso / SPID en un nodo separado.


Podría estar malinterpretando esto, pero ¿esta información no prueba que el problema no es la escalada de bloqueo? Una sección citada dice "look at the blocked process report details.", y el XML más destacado en la pregunta es el informe de proceso bloqueado. A continuación, dice la misma sección citada "If waitresource starts with KEY or PAG instead of OBJECT, then lock escalation isn’t involved in that specific block.", y se muestra el XML de informe de proceso bloqueado waitresource="KEY: 6:72057..... Eso significa que "la escalada de bloqueo no está involucrada" aquí.
Solomon Rutzky

No, NO estás malinterpretando esto. La sección que se proporciona en la pregunta es un problema en este servidor. Mi respuesta es un enfoque global a los problemas que podrían ocurrir debido al bloqueo y la escalada de bloqueo. Si puede solucionar algunos problemas importantes (blocks_process_reports para el bloqueo de nivel OBJECT), entonces los problemas más pequeños (blocks_process_reports en otros niveles) pueden resolverse por sí mismos. Esta es la razón por la que también he agregado una segunda respuesta alternativa.
John aka hot2use
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.