Leerer Blockierungsprozess im Blockierungsprozessbericht

28

Ich sammle gesperrte Prozessberichte mit Extended Events und aus irgendeinem Grund ist der blocking-processKnoten in einigen Berichten leer. Dies ist die vollständige XML:

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

Die Indexdefinition für den Index, zu dem diese hobt_id gehört, lautet

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

Es ist keine Partitionierung erforderlich. Dies ist die Tabellendefinition:

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

In keiner der Tabellen in der gesamten Datenbank sind Trigger oder Fremdschlüssel definiert.

Der genaue SQL Server-Build lautet:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
23. Juni 2016, 17:45:11 Uhr Copyright (c) Microsoft Corporation Enterprise Edition: Kernbasierte Lizenzierung (64-Bit) unter Windows NT 6.3 ( Build 14393:) (Hypervisor)

Die erweiterten Ereignisse sind recht einfach und protokollieren lediglich die blockierten Prozessberichte:

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

Die Datenbank wird in Read Committed Snapshot Isolation konfiguriert, und der maximale Parallelitätsgrad ist auf 1 festgelegt. Dies ist die Serverkonfiguration:

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

Ich habe eine Zeit lang eine serverseitige Ablaufverfolgung ausgeführt, und in einer Ablaufverfolgungsdatei werden dieselben leeren Knoten angezeigt wie bei Verwendung von erweiterten Ereignissen.
Dieser blockierte Prozessbericht wurde mithilfe einer serverseitigen Ablaufverfolgung auf einem anderen Server erfasst, auf dem auch Dynamics AX ausgeführt wird, sodass er nicht für diesen Server oder Build spezifisch ist.

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

Hat jemand eine Erklärung für diese Berichte? Was blockiert die Abfrage?

Gibt es eine Möglichkeit herauszufinden, was passiert ist, wenn ich mir die Berichte ansehe, nachdem die Schlösser längst verschwunden sind?

Eine Sache, die nützlich sein könnte, ist, dass diese Abfragen über sp_cursorprepareund ausgeführt werdensp_cursorexecute

Bisher konnte ich es nicht reproduzieren, es scheint zufällig, aber sehr oft vorzukommen.

Dies geschieht in mehreren Instanzen (unterschiedlicher Builds) und in mehreren Tabellen / Abfragen, die sich alle auf Dynamics AX beziehen.

Derzeit werden im Hintergrund keine Index- oder anderen Datenbankwartungsjobs ausgeführt.

Unter Verwendung des Codes, der in der Antwort von Srutzky bereitgestellt wurde, konnte ich einige Protokollierungen im Zusammenhang mit diesem blockierten Prozessbericht erfassen:

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

Dies ist in den Protokollierungstabellen für dieselbe Ressource zu dieser Zeit zu finden: Gist wegen Zeichenbeschränkung

Weitere Untersuchungen haben ergeben, dass ich kurz vor und nach dem Bericht mit einem leeren Blockierungsprozess Berichte für dieselbe Ressourcen-ID habe, die blockierende Prozessknoten haben:

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

Mit dem neuen Skript von srutzky wurden neue Daten gesammelt. Es ist wegen der maximalen Postlänge auf Github gepostet .

Da die ursprünglich geposteten Daten nicht beide Sitzungs- IDs hatten, wurden einige neue Daten erneut auf github gepostet

Neue Daten einschließlich der Verbindungen auf Github

Tom V - Team Monica
quelle

Antworten:

6

Ich kann diese Theorie derzeit nicht testen, aber basierend auf den neuesten Capture-Daten, die an GitHub gesendet wurden , würde ich sagen, dass der Grund dafür, dass der <process>Knoten leer ist, darin besteht, dass eine aktuell ausgeführte Anforderung erforderlich ist (viele der Attribute befinden sich in sys.dm_exec_requestsund nicht in sys.dm_exec_sessions) und ohne aktuell ausgeführte Anforderung können keine Details gemeldet werden, ähnlich wie beim Ausführen einer INNER JOINZwischenanforderung, sys.dm_exec_requestsund es sys.dm_exec_sessionswerden Zeilen ausgeschlossen, in denen eine Sitzung aktiv ist, die jedoch aufgrund keiner aktuellen Anforderung inaktiv ist.

Wenn Sie sich den oberen Datensatz ( monitorLoopWerte: 1748823, 1748824, 1748825 und 1748827) ansehen, sehen Sie Folgendes:

  • Das idvon blocked-processist in jedem Fall dasselbe: process2552c1fc28 , und das einzige Attribut, das sich unterscheidet, ist das waittime(verständlicherweise).
  • Die Attribute der blocking-processKnoten zeigen Unterschiede in beiden lastbatchstartedundlastbatchcompleted
  • Die Attribute der blocking-processKnoten zeigen identische Werte für spidundxactid

Wie können die Sitzungs-ID und die Transaktions-ID des Blockierungsprozesses in 4 verschiedenen Abfragestapeln identisch sein? Einfach, eine explizite Transaktion wurde gestartet und dann wurden diese Chargen ausgeführt. Und da es sich um separate Stapel handelt, wird zwischen den einzelnen Stapeln eine Zeitspanne liegen, in der keine aktuelle Anforderung vorliegt und daher keine Prozessinformationen angezeigt werden müssen (die Sitzung und die Transaktion sind jedoch noch vorhanden).

Um dies genauer zu untersuchen, können Sie hilfreiche Informationen von sys.dm_exec_requestsund sys.dm_tran_locksdurch Platzieren des folgenden T-SQL in einem Auftragsschritt "Transaction-SQL-Skript (T-SQL)" des SQL Server-Agenten erfassen und die "Datenbank" als "Datenbank" festlegen Eine, die Sie untersuchen (in diesem Fall die mit der ID 6), und planen, dass dieser Job alle 10 Sekunden ausgeführt wird. Das folgende T-SQL erstellt die beiden Tabellen in derselben Datenbank, wenn sie nicht vorhanden sind, und füllt dann die Tabelle "Requests" (Anforderungen), wenn eine Anforderung sich selbst blockiert oder wenn eine Lösch- oder Aktualisierungsoperation blockiert wird . Wenn Anforderungen gefunden werden, wird versucht, Folgendes zu erfassen:

  • Sitzungs- und Anforderungsinformationen zum Blockierungsprozess (in diesem Teil wird nicht davon ausgegangen, dass eine aktive Anforderung vorhanden ist, sodass RIGHT JOINmindestens die Sitzungsinformationen abgerufen werden müssen.)
  • Verbindungsinformationen für die gesperrten und (hoffentlich) gesperrten Prozesse.
  • die aktuellen Sperren für die gleiche Sitzungs_ID der (nur im Kopf behalten , dass die Sperre info ist nicht garantiert zu 100% genau zu sein , wie die Informationen in der Zeit zwischen diesen beiden Anweisungen ausführen ändern, noch die Informationen gut genug oft genug zu sein wert zu erfassen). Dieser Abschnitt ist derzeit auskommentiert.

T-SQL-Auftragsschritt des SQL Server-Agenten:

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

Ich denke, Sie sollten dies reproduzieren können, indem Sie einen Abfrage-Tab öffnen und Folgendes ausführen:

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

Öffnen Sie dann eine zweite Abfrage-Registerkarte und führen Sie Folgendes aus:

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

PS Nur um es so auszudrücken, das einzige, was keinen Sinn ergibt, ist, dass die Anfrage- und Sitzungsinformationen - dbo.tmpBlockingResearch_Requests- immer noch keine Zeilen für die blockierende Sitzung enthalten. Ich weiß jedoch, dass die Tabellenvariable die blockierende Sitzungs-ID enthält, da sie die Sperren für beide Sitzungs-IDs aktiviert hat. Dies könnte auf ein Szenario hindeuten, in dem eine Transaktion geöffnet bleiben darf, nachdem die "Verbindung" vom Client geschlossen wurde, die Verbindung jedoch aufgrund des Verbindungspools weiterhin aufrecht erhalten wird.

Solomon Rutzky
quelle
@TomV Ich habe die neuesten Forschungsdaten überprüft und habe eine ziemlich solide Theorie. Ich habe meine Antwort entsprechend aktualisiert, einschließlich des Hinzufügens eines Abschnitts zu meinen Rechercheabfragen. Ersetzen Sie daher bitte den Jobschritt SQL durch die neuen Abfragen hier es sind viele Daten). Ich schlage vor, die vorhandenen Forschungstabellen abzuschneiden / zu löschen, um von vorne zu beginnen.
Solomon Rutzky
@TomV Ok. Und ich habe meine Repro-Abfrage so aktualisiert, dass sie ein UPDATE anstelle eines SELECT ist, sodass sie sowieso repräsentativer für Ihre Situation ist. Außerdem habe ich am Ende einen Hinweis zu fehlenden Zeilen in der Anforderungstabelle hinzugefügt. Hoffentlich bestätigt die neue Verbindungstabelle zumindest das Fortbestehen der blockierenden SessionID. (PS, ich habe angefangen, meine Kommentare oben zu bereinigen).
Solomon Rutzky
Ihr Job ist aktiv. Ich brauche etwas Zeit, um den Repro zu testen und ihn nächste Woche zu analysieren
Tom V - Team Monica
Hallo Solomon. Auf github wurden 2 neue Beispiele gepostet. Leider konnte ich mit dem mitgelieferten Reprofall keinen Leersperrvorgang BPR auslösen.
Tom V - Team Monica
Ich habe einen kurzen Blick darauf geworfen, da ich nicht viel Zeit habe. Es sieht so aus, als ob in den Verbindungsinformationen die blockierende Sitzungs-ID angezeigt wird, die jedoch nicht in der Sitzungstabelle enthalten ist. Ich kann das später testen, aber ich bin mir ziemlich sicher, dass dies auf Verbindungspooling hinweist (Verbindung ist immer noch vorhanden) und die Verbindung zwischen Befehlen geschlossen ist, obwohl eine Transaktion offen ist (da die transaction_id immer dieselbe ist, wie wir sie beim letzten Mal gesehen haben). Werde später genauer hinsehen ..
Solomon Rutzky
4

Gesperrte Transaktionen können aufgrund von Sperreneskalationen auftreten.

Dies wird im Microsoft Support-Artikel erläutert:

Beheben von Blockierungsproblemen, die durch Sperreneskalation in SQL Server verursacht werden

...
Sperrenausweitung verursacht die meisten Blockierungsprobleme nicht. Starten Sie eine SQL Profiler-Ablaufverfolgung, die das Ereignis Lock: Escalation enthält, um zu ermitteln, ob eine Sperreneskalation zu einem Zeitpunkt auftritt, an dem Blockierungsprobleme auftreten. Wenn keine Lock: Escalation-Ereignisse angezeigt werden, tritt auf Ihrem Server keine Lock-Eskalation auf, und die Informationen in diesem Artikel gelten nicht für Ihre Situation.

Wenn eine Sperreneskalation auftritt, vergewissern Sie sich, dass die eskalierte Tabellensperre andere Benutzer blockiert
...

Überprüfen Sie die erweiterten Ereignisse (physische Datei) auf Sperreneskalationsereignisse , die vor dem Ereignis des blockierten Prozesses aufgetreten sind .

Erklären

Es gibt einen Microsoft Blog-Artikel, der weitere Einzelheiten enthält:

Eskalation und Blockierung von SQL Server-Sperren

...
Schritt 2: Ereignisse für Sperreneskalation und blockierten Prozessbericht erfassen.

Sperrenausweitung und blockierte Prozessberichtereignisse werden von SQL Server nicht automatisch erfasst. Um zu wissen, ob diese Ereignisse eintreten, müssen wir SQL Server anweisen, sie aufzuzeichnen. Unser Team verwendet das Tool Performance Analyzer für Microsoft Dynamics, um diese Informationen zu erfassen. In diesem Beitrag von Rod Hansen finden Sie weitere Informationen zum Tool und zum Sammeln von Blockierungsdetails. Wenn Sie nur SQL Server Profiler verwenden möchten, werden die Ereignisse, die Sie sammeln müssten, unten angezeigt: ...

Nachdem Sie Sperreneskalationen und blockierte Prozesse erfasst haben, müssen Sie feststellen, ob die Sperreneskalationen die Hauptursache für die blockierten Prozesse sind:

...
Schritt 3: Überprüfen Sie die Ablaufverfolgung in SQL Server Profiler.

Es gibt zwei Hauptindikatoren, die Ihnen mitteilen, ob die Blockierung mit der Sperreneskalation zusammenhängt.

Zunächst wird eine Reihe von Sperreneskalationsereignissen angezeigt, die den Ereignissen für blockierte Prozessberichte unmittelbar vorangehen. Im Folgenden finden Sie ein Beispiel aus einer vom Performance Analyzer für Microsoft Dynamics-Tool erstellten Ablaufverfolgung. Dies ist eine Sache, auf die im Trace geachtet werden muss, aber dies allein bedeutet nicht, dass die Sperreneskalation die Blockierung verursacht. ...

und weiter

Um zu überprüfen, ob die Blockierung tatsächlich mit der Sperreneskalation zusammenhängt, müssen Sie die Details des blockierten Prozessberichts überprüfen. Suchen Sie im Abschnitt TextData nach waitresource (siehe Abbildung unten). Wenn waitresource mit OBJECT beginnt, ist bekannt, dass die blockierte Anweisung auf die Freigabe einer Sperre auf Tabellenebene wartet, bevor sie fortgesetzt werden kann. Wenn waitresource mit KEY oder PAG anstelle von OBJECT beginnt, ist die Sperreneskalation in diesem bestimmten Block nicht beteiligt . Durch die Eskalation von Sperren wird der Gültigkeitsbereich einer Sperre für OJBECT immer vergrößert, unabhängig davon, wo sie gestartet wird

Lösung

(nur wenn die oben genannten übereinstimmen)

Die Lösung besteht anscheinend darin, das Ablaufverfolgungsflag 1224 zu aktivieren, das die Sperreneskalation ausschaltet:

Eskalation und Blockierung von SQL Server-Sperren

Wenn Sie diese beiden Dinge zusammen sehen, ist es eine gute Wette, dass die Sperreneskalation die Blockierung verursacht, und Sie würden wahrscheinlich von der Implementierung des SQL Server-Ablaufverfolgungsflags 1224 profitieren.

SQL Server-Ablaufverfolgungsflags für Dynamics AX

Das Ablaufverfolgungsflag 1224 deaktiviert die Sperreneskalation basierend auf der Anzahl der Sperren. Das Aktivieren dieses Ablaufverfolgungsflags kann die Wahrscheinlichkeit des Blockierens aufgrund von Sperreneskalation verringern, wie ich es bei einer Reihe von AX-Implementierungen gesehen habe. Das häufigste Szenario, in dem dies zu einem Problem wird, besteht darin, dass die Masterplanung tagsüber ausgeführt werden muss

Antworten

Am Ende könnte es sein, dass die Sperreneskalation die Hauptursache für blockierte Prozesse ist.


Alternative Lösung (Prozessknoten leer)

Nach weiteren Untersuchungen einiger blockierter_Prozessberichte kann die folgende alternative Erklärung abgegeben werden.

Die erweiterten Ereignisse erfassen blockierte_Prozessberichte, die zu diesem Zeitpunkt keine Beziehung zu anderen Prozessen haben.

Ergo: Sie müssen aus einem anderen Grund gesperrt werden

Ich würde vorschlagen, dass Sie einen Zeitrahmen von Wartetypen aus der Sicht sys.dm_os_wait_stats auf Ihrem SQL Server erfassen und die Zahlen mit den blockierten_Prozessberichten korrelieren, die während Ihrer Messungen auftreten. Paul Randall hat ein gutes Skript: Schicken Sie mir Ihre Wartestatistik und holen Sie sich meinen Rat und 30 Tage kostenlose Pluralsight-Gegenleistung

Das Skript erfasst die aktuellen Leistungsindikatoren, wartet 23 Stunden (kann geändert werden), erfasst die aktuellen Leistungsindikatoren erneut und vergleicht sie, um die besten 95% der Wartetypen zu erhalten. Sie können dies beispielsweise 1 Stunde lang ausprobieren und die XEL-Datei zur Hand haben.

Möglicherweise finden Sie einen Wartetyp (z. B. LCK_M_SH, ...), der Ihnen mitteilt, dass Ihr Speicher langsam ist. Oder dass Sie einen anderen Overhead haben (zB CX_PACKET_WAITS, ...). Etwas verlangsamt Ihre Updates. Sie können dann sehen, ob die sys.dm_os_wait_stats mit den blockierten_Prozessberichten mit den leeren Knoten zusammenhängen.

Es gibt Fälle, in denen eine blockierte SPID von derselben SPID blockiert wird:

Die blockierte Spalte in der Sysprocesses-Tabelle wird nach der Installation von SQL Server 2000 SP4 für Wartezeiten aufgefüllt

Wenn eine SPID auf einen E / A-Seitenzwischenspeicher wartet, stellen Sie möglicherweise fest, dass die blockierte Spalte kurz meldet, dass die SPID sich selbst blockiert. Dieses Verhalten ist ein Nebeneffekt der Art und Weise, wie Latches für E / A-Vorgänge auf Datenseiten verwendet werden. Wenn ein Thread eine E / A-Anforderung ausgibt, erhält die SPID, die die E / A-Anforderung ausgibt, einen Latch auf der Seite. Alle SQL Server 2000-E / A-Vorgänge sind asynchron. Daher versucht die SPID, ein anderes Latch auf derselben Seite abzurufen, wenn die SPID, die die E / A-Anforderung ausgegeben hat, auf den Abschluss der Anforderung warten muss. Diese zweite Verriegelung wird von der ersten Verriegelung blockiert. Daher meldet die blockierte Spalte, dass die SPID sich selbst blockiert. Wenn die E / A-Anforderung beendet ist, wird die erste Verriegelung freigegeben. Dann wird die zweite Zwischenspeicheranforderung gewährt.

Alternative Antwort

Dies ist ein weiterer Hinweis darauf, dass möglicherweise E / A-Probleme vorliegen. Diese Probleme führen zu "blockierten Prozessen", jedoch ohne zugehörige fremde SPID. Bei erweiterten Ereignissen wird der Prozess / die SPID möglicherweise nicht in einem separaten Knoten gemeldet.

John aka hot2use
quelle
Ich könnte dies falsch verstehen, aber beweisen diese Informationen nicht, dass das Problem keine Sperreneskalation ist? In einem zitierten Abschnitt heißt es "look at the blocked process report details.", und das XML mit der höchsten Priorität in der Frage ist der Bericht über blockierte Prozesse. Als Nächstes wird im selben zitierten Abschnitt "If waitresource starts with KEY or PAG instead of OBJECT, then lock escalation isn’t involved in that specific block."und im XML-Bericht über blockierte Prozesse angegeben waitresource="KEY: 6:72057..... Das bedeutet also, dass hier keine Sperreneskalation erfolgt.
Solomon Rutzky
Nein, Sie verstehen das NICHT falsch. Der Abschnitt, der in der Frage bereitgestellt wird, ist ein Problem auf diesem Server. Meine Antwort ist ein globaler Ansatz für Probleme, die aufgrund von Blockierungen und Sperreneskalationen auftreten können. Wenn Sie einige wichtige Probleme beheben können (blocks_process_reports für das Sperren von OBJECT-Ebenen), können sich die kleineren Probleme (blocks_process_reports auf anderen Ebenen) von selbst beheben lassen. Aus diesem Grund habe ich auch eine zweite alternative Antwort hinzugefügt.
John aka hot2use