Svuotare il processo di blocco nel report del processo bloccato


28

Sto raccogliendo rapporti di processo bloccati utilizzando Eventi estesi e per qualche motivo in alcuni rapporti il blocking-processnodo è vuoto. Questo è il file 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 definizione dell'indice per l'indice a cui appartiene hobt_id è

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

Non è previsto il partizionamento, questa è la definizione della tabella:

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

Non ci sono trigger o chiavi esterne definite su nessuna delle tabelle nell'intero database.

La build esatta di SQL Server è:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
23 giu 2016 17:45:11 Copyright (c) Microsoft Corporation Enterprise Edition: licenze basate su core (64 bit) su Windows NT 6.3 ( Build 14393:) (Hypervisor)

Gli eventi estesi sono abbastanza semplici, registrando semplicemente i rapporti di processo bloccati:

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

Il database è configurato in Read Committed Snapshot Isolation e il grado massimo di parallelismo è impostato su 1. Questa è la configurazione del server:

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

Ho eseguito una traccia lato server per un po 'e ottengo gli stessi nodi vuoti in un file di traccia come faccio usando eventi estesi.
Questo report di processo bloccato è stato acquisito utilizzando una traccia lato server su un altro server che esegue anche Dynamics AX, quindi non è specifico per questo server o build.

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

Qualcuno ha una spiegazione per questi rapporti? Cosa sta bloccando la query?

C'è un modo per scoprire cosa stava succedendo se sto guardando i rapporti dopo che i blocchi sono passati da tempo?

Una cosa che potrebbe essere utile aggiungere è che queste query vengono eseguite tramite sp_cursorprepareesp_cursorexecute

Finora non sono stato in grado di riprodurlo, sembra accadere casualmente ma molto spesso.

Succede in diverse istanze (di diverse build) e diverse tabelle / query, tutte relative a Dynamics AX.

Al momento non ci sono indici o altri lavori di manutenzione del database in background.

Utilizzando il codice fornito nella risposta di srutzky sono stato in grado di acquisire alcune registrazioni relative a questo report di processo bloccato:

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

Questo si trova nelle tabelle di registrazione per la stessa risorsa in quel periodo: Gist a causa del limite di caratteri

Ulteriori indagini mostrano che appena prima e dopo il rapporto con un processo di blocco vuoto ho rapporti per lo stesso id risorsa che hanno nodi del processo di blocco:

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

Utilizzando il nuovo script fornito da srutzky sono stati raccolti nuovi dati. È pubblicato su github a causa della lunghezza massima del post.

Poiché i dati originariamente pubblicati non avevano entrambi gli ID di sessione, alcuni nuovi dati sono stati nuovamente pubblicati su github

Nuovi dati tra cui le connessioni su github

Risposte:


6

Al momento non posso testare questa teoria, ma in base ai dati di acquisizione più recenti pubblicati su GitHub , direi che il motivo per cui il <process>nodo è vuoto è che richiede una richiesta attualmente in esecuzione (molti degli attributi si trovano in sys.dm_exec_requestse non in sys.dm_exec_sessions) e senza una richiesta attualmente in esecuzione, non è in grado di riportare alcun dettaglio, in modo analogo a come si fa un INNER JOINintermediario sys.dm_exec_requestsed sys.dm_exec_sessionsescluderà le righe in cui una sessione è attiva ma è inattiva a causa della richiesta corrente.

Osservando la serie superiore di dati ( monitorLoopvalori: 1748823, 1748824, 1748825 e 1748827) possiamo vedere quanto segue:

  • il idof blocked-processè lo stesso in ogni caso: process2552c1fc28 e l'unico attributo diverso è waittime(comprensibilmente).
  • gli attributi dei blocking-processnodi mostrano differenze in entrambi lastbatchstartedelastbatchcompleted
  • gli attributi dei blocking-processnodi mostrano valori identici per spidexactid

Quindi, in che modo SessionID e TransactionID del processo di blocco possono essere gli stessi in 4 diversi batch di query? Facile, è stata avviata una transazione esplicita e quindi questi batch sono stati eseguiti. E poiché questi sono lotti separati, c'è un tempo tra loro per essere inoltrato, a quel punto non vi è alcuna richiesta corrente, quindi nessuna informazione di processo da mostrare (ma la sessione e la transazione sono ancora lì).

Per fare ulteriori ricerche in merito, è possibile acquisire informazioni utili da sys.dm_exec_requestse sys.dm_tran_locksinserendo il seguente T-SQL in un passaggio di processo "Transaction-SQL script (T-SQL)" dell'agente di SQL Server, impostando il "Database" come uno che stai cercando (in questo caso è quello con un ID di 6) e pianifica l'esecuzione di questo lavoro ogni 10 secondi. Il T-SQL seguente creerà le due tabelle nello stesso DB se non esistono e quindi popolerà la tabella "Richieste" se una richiesta si sta bloccando o se è un'operazione di eliminazione o aggiornamento che viene bloccata . Se vengono trovate richieste, tenterà di acquisire:

  • Informazioni sulla sessione e la richiesta sul processo di blocco (questa parte non presuppone l'esistenza di una richiesta attiva, quindi RIGHT JOINalmeno per ottenere le informazioni sulla sessione)
  • Informazioni sulla connessione per i processi bloccati e (si spera) bloccanti.
  • i blocchi attuali per quegli stessi session_id (tieni presente che le informazioni sui blocchi non sono garantite per essere accurate al 100% in quanto tali informazioni possono cambiare nel tempo tra quelle due istruzioni in esecuzione; tuttavia, le informazioni sono abbastanza buone abbastanza spesso da essere vale la pena catturare). Questa sezione è attualmente commentata.

Passaggio del processo T-SQL di SQL Server Agent:

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

Penso che dovresti essere in grado di riprodurlo aprendo una scheda della query ed eseguendo quanto segue:

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

Quindi, apri una seconda scheda della query ed esegui quanto segue:

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

PS Giusto per dirlo, l'unica cosa che non ha senso è che le informazioni su richiesta e sessione dbo.tmpBlockingResearch_Requests- non contengono ancora righe per la sessione di blocco. Tuttavia, so che la variabile della tabella contiene l'ID della sessione di blocco in quanto ha inserito i blocchi per entrambi gli SessionID. Ciò potrebbe indicare uno scenario in cui una transazione può rimanere aperta dopo che la "connessione" dal client è stata chiusa ma la connessione viene comunque mantenuta a causa del pool di connessioni.


@TomV Ho esaminato i dati di ricerca più recenti e ho una teoria abbastanza solida. Ho aggiornato la mia risposta di conseguenza, inclusa l'aggiunta di una sezione alle mie query di ricerca, quindi si prega di sostituire il passaggio del processo SQL con le nuove query qui (ho anche commentato la query "blocchi" poiché non abbiamo davvero bisogno di quei dati in questo momento e sono molti dati). Suggerisco di troncare / far cadere le tabelle di ricerca esistenti per ricominciare da capo.
Solomon Rutzky,

@TomV Ok. E ho aggiornato la mia query di riproduzione in modo che sia un AGGIORNAMENTO anziché un SELECT, quindi dovrebbe essere comunque più rappresentativo della tua situazione. Ho anche aggiunto una nota alla fine sulle righe mancanti nella tabella delle richieste. Si spera che la nuova tabella Connections confermi almeno l'esistenza del SessionID di blocco. (PS, ho iniziato a ripulire i miei commenti sopra).
Solomon Rutzky,

Il tuo lavoro è attivo Dovrò trovare un po 'di tempo per testare la riproduzione e analizzarla la prossima settimana
Tom V - Team Monica,

Ciao Salomone. 2 nuovi esempi sono stati pubblicati su github. Sfortunatamente non ho potuto innescare un processo di blocco vuoto BPR usando il caso di riprogrammazione fornito.
Tom V - Team Monica,

Ho dato un'occhiata molto veloce perché non ho molto tempo. Sembra che le informazioni di Connections mostrino l'ID della sessione di blocco ancora attivo ma non si trova nella tabella delle sessioni. Posso provarlo più tardi, ma sono abbastanza sicuro che indica il pool di connessioni (la connessione è ancora lì) e la connessione viene chiusa tra i comandi, ma una transazione è chiaramente aperta (poiché la transazione_id è sempre la stessa che abbiamo visto l'ultima volta).
Daremo

4

Le transazioni bloccate possono verificarsi a causa di escalation di blocchi.

Questo è spiegato nell'articolo del supporto Microsoft:

Come risolvere i problemi di blocco causati dall'escalation dei blocchi in SQL Server

... L'
escalation dei blocchi non causa la maggior parte dei problemi di blocco. Per determinare se l'escalation dei blocchi si sta verificando nel momento in cui si verificano problemi di blocco, avviare una traccia di SQL Profiler che include l'evento Lock: Escalation. Se non vedi alcun evento Lock: Escalation, l'escalation del blocco non si sta verificando sul tuo server e le informazioni contenute in questo articolo non si applicano alla tua situazione.

Se si verifica l'escalation del blocco, verificare che il blocco della tabella con escalation blocchi altri utenti
...

Controllare gli Eventi estesi (file fisico) per gli eventi di escalation dei blocchi verificatisi prima dell'evento di processo bloccato .

spiegando

C'è un articolo di Microsoft Blog che approfondisce ulteriormente:

Escalation e blocco dei blocchi di SQL Server

...
Passaggio 2: Raccogliere gli eventi di escalation blocco e report processi bloccati.

L'escalation dei blocchi e gli eventi dei report dei processi bloccati non vengono acquisiti automaticamente da SQL Server. Per sapere se si verificano questi eventi, è necessario indicare a SQL Server di registrarli. Il nostro team utilizza lo strumento Performance Analyzer per Microsoft Dynamics per raccogliere tali informazioni. Dai un'occhiata a questo post di Rod Hansen per ulteriori informazioni sullo strumento e su come raccogliere i dettagli di blocco con esso. Se desideri solo utilizzare SQL Server Profiler, gli eventi che dovresti raccogliere sono mostrati di seguito: ...

Dopo aver acquisito le escalation dei blocchi e i processi bloccati, è necessario determinare se le escalation dei blocchi sono la causa principale dei processi bloccati:

...
Passaggio 3: rivedere la traccia in SQL Server Profiler.

Esistono due indicatori principali che indicano se il blocco è correlato all'escalation del blocco.

Innanzitutto, vengono visualizzati una serie di eventi di escalation dei blocchi che precedono immediatamente gli eventi del report del processo bloccato. Di seguito è riportato un esempio tratto da una traccia prodotta dallo strumento Performance Analyzer per Microsoft Dynamics. Questa è una cosa da cercare nella traccia, ma questo da solo non significa che l'escalation del blocco sta causando il blocco. ...

e inoltre

Per verificare che il blocco sia effettivamente correlato all'escalation dei blocchi, è necessario esaminare i dettagli del report di processo bloccato. Nella sezione TextData cerca waitresource (vedi la schermata qui sotto). Se waitresource inizia con OBJECT, sappiamo che l'istruzione bloccata è in attesa di un blocco a livello di tabella per essere rilasciata prima che possa procedere. Se waitresource inizia con KEY o PAG anziché OBJECT, l' escalation dei blocchi non è coinvolta in quel blocco specifico . L'escalation dei blocchi aumenterà sempre la portata di un blocco su OJBECT indipendentemente da dove inizia

Soluzione

(solo se le corrispondenze sopra menzionate)

Apparentemente la soluzione è attivare il flag di traccia 1224 che disattiverà l'escalation del blocco:

Escalation e blocco dei blocchi di SQL Server

Se vedi queste due cose insieme, è una buona scommessa che l'escalation del blocco sta causando il blocco e probabilmente trarrai vantaggio dall'implementazione del flag di traccia di SQL Server 1224.

Flag di traccia di SQL Server per Dynamics AX

Il flag di traccia 1224 disabilita l'escalation dei blocchi in base al numero di blocchi. L'abilitazione di questo flag di traccia può ridurre la probabilità di blocco a causa dell'escalation del blocco, cosa che ho visto con una serie di implementazioni AX. Lo scenario più comune in cui questo diventa un problema è quando è necessario che Pianificazione generale venga eseguita durante il giorno

Risposta

Alla fine potrebbe essere che l'escalation dei blocchi sia la causa principale dei processi bloccati.


Soluzione alternativa (nodo del processo vuoto)

Dopo ulteriori indagini su alcuni blocchi_processo_tiportati, è possibile fornire la seguente spiegazione alternativa.

Gli eventi estesi stanno catturando block_process_reports che non sono correlati a nessun altro processo in quel momento.

Ergo: devono essere bloccati per un motivo diverso

Ti suggerirei di acquisire un intervallo di tipi di attesa dalla vista sys.dm_os_wait_stats sul tuo SQL Server e di correlare i numeri con i blocchi_processo_attivi che si verificano durante le tue misurazioni. Paul Randall ha una buona sceneggiatura: inviami le tue statistiche di attesa e ricevi in ​​cambio i miei consigli e 30 giorni di Pluralsight gratis

Gli script acquisiscono i contatori correnti, attendono 23 ore (possono essere modificati), ricatturano di nuovo i contatori correnti e li confrontano per offrirti il ​​95% dei tipi di attesa migliori. Puoi provarlo per dire 1 ora e avere il file XEL a portata di mano.

Potresti trovare un tipo di attesa (ad esempio LCK_M_SH, ...) che ti dice che la tua memoria è lenta nella scrittura. O che hai qualche altro overhead (es. CX_PACKET_WAITS,….). Qualcosa sta rallentando i tuoi aggiornamenti. È quindi possibile vedere se sys.dm_os_wait_stats si riferiscono a Block_Process_reports con i nodi vuoti.

Ci sono casi in cui uno SPID bloccato viene bloccato dallo stesso SPID:

La colonna bloccata nella tabella sysprocesses viene popolata per le attese di latch dopo l'installazione di SQL Server 2000 SP4

Quando uno SPID è in attesa di un blocco della pagina I / O, è possibile notare che la colonna bloccata segnala brevemente che lo SPID si sta bloccando. Questo comportamento è un effetto collaterale del modo in cui i latch vengono utilizzati per le operazioni di I / O nelle pagine di dati. Quando un thread emette una richiesta I / O, lo SPID che emette la richiesta I / O acquisisce un latch nella pagina. Tutte le operazioni di I / O di SQL Server 2000 sono asincrone. Pertanto, lo SPID proverà ad acquisire un altro latch nella stessa pagina se lo SPID che ha emesso la richiesta I / O deve attendere il completamento della richiesta. Questo secondo fermo è bloccato dal primo fermo. Pertanto, la colonna bloccata segnala che lo SPID si sta bloccando. Al termine della richiesta I / O, viene rilasciato il primo latch. Quindi, viene concessa la seconda richiesta di blocco.

Risposta alternativa

Questa è un'ulteriore indicazione che potresti avere problemi di I / O. Questi problemi comportano "processi bloccati" ma senza un SPID esterno correlato. Gli eventi estesi potrebbero non riportare il processo / SPID in un nodo separato.


Potrei leggere male questo, ma queste informazioni non dimostrano che il problema non è l' escalation del blocco? Una sezione citata dice "look at the blocked process report details.", e l'XML più in alto nella domanda è il rapporto di processo bloccato. Successivamente, dice la stessa sezione tra virgolette "If waitresource starts with KEY or PAG instead of OBJECT, then lock escalation isn’t involved in that specific block."e viene mostrato l'XML del report di processo bloccato waitresource="KEY: 6:72057..... Ciò significa che "l'escalation dei blocchi non è coinvolta" qui.
Solomon Rutzky,

No, NON stai leggendo male questo. La sezione fornita nella domanda è un problema su questo server. La mia risposta è un approccio globale ai problemi che potrebbero verificarsi a causa del blocco e del blocco dell'escalation. Se è possibile risolvere alcuni problemi importanti (Block_Process_report per il blocco del livello OBJECT), i problemi più piccoli (Block_Process_report ad altri livelli) potrebbero risolversi. Questo è il motivo per cui ho anche aggiunto una seconda risposta alternativa.
John aka hot2use
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.