Пустой процесс блокировки в отчете о заблокированных процессах

28

Я собираю отчеты о заблокированных процессах с использованием расширенных событий, и по некоторым причинам в некоторых отчетах blocking-processузел пуст. Это полный 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>

Определение индекса для индекса, к которому принадлежит 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

Нет никакого разделения, это определение таблицы:

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

Ни в одной из таблиц во всей базе данных не определены триггеры или внешние ключи.

Точная сборка SQL Server:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
23 июня 2016 г. 17:45:11 Copyright (c) Microsoft Corporation Enterprise Edition: лицензирование на основе ядра (64-разрядная версия) в Windows NT 6.3 ( Сборка 14393:) (Гипервизор)

Расширенные события довольно просты, просто регистрируя отчеты о заблокированных процессах:

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

База данных настроена в режиме Read Committed Snapshot Isolation, и максимальная степень параллелизма установлена ​​в 1. Это конфигурация сервера:

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

Некоторое время я запускал трассировку на стороне сервера и получал те же пустые узлы в файле трассировки, что и при использовании расширенных событий.
Этот отчет о заблокированных процессах был получен с помощью трассировки на стороне сервера на другом сервере, на котором также работает Dynamics AX, поэтому он не относится к этому серверу или сборке.

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

У кого-нибудь есть объяснение этим сообщениям? Что блокирует запрос?

Есть ли способ узнать, что происходит, если я просматриваю отчеты после того, как замки давно исчезли?

Единственное , что может быть полезно добавить, что эти запросы выполняются с помощью sp_cursorprepareиsp_cursorexecute

До сих пор я не смог воспроизвести это, кажется, что это происходит случайно, но очень часто.

Это происходит в нескольких случаях (разных сборок) и в нескольких таблицах / запросах, связанных с Dynamics AX.

В настоящее время в фоновом режиме не выполняются никакие задания по обслуживанию индекса или других баз данных.

Используя код, предоставленный srutzky в ответе, я смог зафиксировать некоторые записи, связанные с этим отчетом о заблокированных процессах:

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

Это можно найти в таблицах журналов для одного и того же ресурса за это время: Gist из-за ограничения по количеству символов

Дальнейшие исследования показывают, что непосредственно перед и после отчета с пустым процессом блокировки у меня есть отчеты для того же ресурса, у которого есть блокирующие узлы процесса:

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

Используя новый скрипт, предоставленный srutzky , были собраны новые данные. Это опубликовано на GitHub из-за максимальной длины сообщения.

Так как первоначально опубликованные данные не имели обоих идентификаторов сессии, некоторые новые данные были снова опубликованы на github.

Новые данные, включая соединения на github

Том V - Команда Моника
источник

Ответы:

6

Я не могу проверить эту теорию в данный момент, но, основываясь на самых последних данных захвата, опубликованных на GitHub , я бы сказал, что причина, по которой этот <process>узел пуст, заключается в том, что он требует выполняющегося в данный момент запроса (многие атрибуты находятся в sys.dm_exec_requestsи не в sys.dm_exec_sessions), и без текущего запущенного запроса он не может сообщить какие-либо подробности, подобно тому, как выполняется INNER JOINпромежуточный запрос, sys.dm_exec_requestsи sys.dm_exec_sessionsисключит строки, в которых сеанс активен, но бездействует из-за отсутствия текущего запроса.

Глядя на верхний набор данных ( monitorLoopзначения: 1748823, 1748824, 1748825 и 1748827), мы можем видеть следующее:

  • idиз blocked-processтакой же в каждом случае: process2552c1fc28 , и единственный атрибут , который отличается является waittime( по понятным причинам ).
  • атрибуты blocking-processузлов показывают различия в обоих lastbatchstartedиlastbatchcompleted
  • атрибуты blocking-processузлов показывают одинаковые значения для spidиxactid

Итак, как SessionID и TransactionID процесса блокировки могут быть одинаковыми для 4 разных пакетов запросов? Легко, явная транзакция была запущена, а затем эти пакеты были выполнены. И поскольку это отдельные пакеты, между ними отправляется время, и в этот момент нет текущего запроса, следовательно, не отображается информация о процессе (но сеанс и транзакция все еще там).

Чтобы провести дополнительное исследование этого вопроса, вы можете получить полезную информацию sys.dm_exec_requestsи sys.dm_tran_locksпоместить следующий T-SQL в шаг задания «Агент Transaction-SQL script (T-SQL)» агента SQL Server, задав для «Базы данных» значение тот, который вы исследуете (в данном случае это тот, у кого есть идентификатор 6), и планируете запускать это задание каждые 10 секунд. Приведенный ниже T-SQL создаст две таблицы в той же БД, если они не существуют, а затем заполнит таблицу «Запросы», если какой-либо запрос либо блокирует сам себя, либо блокируется операция удаления или обновления. , Если какие-либо запросы найдены, он попытается перехватить:

  • Информация о сеансе и запросе о процессе блокировки (эта часть не предполагает наличие активного запроса, следовательно, RIGHT JOINпо крайней мере, чтобы получить информацию о сеансе)
  • Информация о подключении для заблокированных и (надеюсь) процессов блокировки.
  • текущие блокировки для тех же идентификаторов сессий (просто имейте в виду, что информация о блокировке не гарантируется на 100% точной, поскольку эта информация может измениться в промежутке между выполнением этих двух операторов; тем не менее, информация достаточно хороша достаточно часто, чтобы стоит захватить). Этот раздел в настоящее время закомментирован.

Шаг задания агента T-SQL агента SQL Server:

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

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

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

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

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

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

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

Я думаю, что вы сможете воспроизвести это, открыв одну вкладку запроса и выполнив следующее:

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

Затем откройте вторую вкладку запроса и выполните следующее:

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

PS Просто чтобы заявить об этом, единственное, что не имеет смысла, - то, что информация запроса и сеанса dbo.tmpBlockingResearch_Requests- все еще никогда не содержит строк для сеанса блокировки. Тем не менее, я знаю, что переменная таблицы содержит блокирующий идентификатор сеанса, поскольку она блокировала оба идентификатора сессии. Это может указывать на сценарий, в котором Транзакции разрешается оставаться открытой после закрытия «соединения» от клиента, но соединение все еще поддерживается из-за пула соединений.

Соломон Руцкий
источник
@ TomV Я рассмотрел новейшие данные исследований и у меня довольно солидная теория. Я соответствующим образом обновил свой ответ, в том числе добавив раздел в свои исследовательские запросы, поэтому замените SQL шага задания новыми запросами здесь (я также закомментировал запрос «блокировки», так как нам сейчас эти данные на самом деле не нужны и это много данных). Я предлагаю обрезать / отбросить существующие таблицы исследований, чтобы начать все заново.
Соломон Руцкий
@ TomV Хорошо. И я обновил мой запрос на репро, чтобы он был ОБНОВЛЕНИЕ вместо ВЫБРАТЬ, так что в любом случае он должен быть более представительным для вашей ситуации. В конце я также добавил примечание о пропущенных строках в таблице запросов. Надеемся, что новая таблица Соединений, по крайней мере, подтвердит продолжение существования блокирующего SessionID. (PS, я начал убирать свои комментарии выше).
Соломон Руцкий
Ваша работа активна. Мне нужно найти время, чтобы протестировать репродукцию и проанализировать ее на следующей неделе
Том V - Команда Моника
Привет Соломон. 2 новых примера были размещены на github. К сожалению, я не смог запустить пустой процесс блокировки BPR, используя предоставленный случай воспроизведения.
Том V - Команда Моника
Взглянул очень быстро, потому что у меня не так много времени. Похоже, информация о соединениях показывает, что идентификатор сеанса блокировки все еще активен, но его нет в таблице сеансов. Я могу проверить это позже, но я почти уверен, что это указывает на пул соединений (соединение все еще существует) и соединение между командами закрыто, но транзакция явно открыта (так как идентификатор транзакции всегда совпадает с тем, что мы видели в прошлый раз). Позже рассмотрим подробнее ..
Соломон Руцкий
4

Блокированные транзакции могут происходить из-за повышения блокировки.

Это объясняется в статье поддержки Microsoft:

Как решить проблемы с блокировкой, вызванные эскалацией блокировки в SQL Server

...
Эскалация блокировки не вызывает большинства проблем блокировки. Чтобы определить, происходит ли повышение блокировки во время возникновения проблем с блокировкой, запустите трассировку SQL Profiler, которая включает в себя событие Lock: Escalation. Если вы не видите никаких событий Lock: Escalation, на вашем сервере не происходит повышение блокировки, и информация в этой статье не относится к вашей ситуации.

Если происходит эскалация блокировки, убедитесь, что эскалация блокировки таблицы блокирует других пользователей
...

Проверьте расширенные события (физический файл) на наличие событий повышения блокировки, которые произошли до события заблокированного процесса .

Объясняя

Есть статья в блоге Microsoft, которая углубляется в детали:

Эскалация и блокировка блокировки SQL Server

...
Шаг 2: Соберите события блокировки эскалации и заблокированных процессов.

Повышение блокировки и события отчета о заблокированных процессах не регистрируются автоматически SQL Server. Чтобы узнать, происходят ли эти события, нам нужно указать SQL Server записать их. Наша команда использует инструмент Performance Analyzer для Microsoft Dynamics для сбора этой информации. Посмотрите этот пост Род Хансена для получения дополнительной информации об инструменте и о том, как собирать информацию о блокировке с его помощью. Если вы просто хотите использовать SQL Server Profiler, события, которые вам нужно собрать, показаны ниже: ...

После того как вы зафиксировали эскалации блокировок и заблокировали процессы, вы должны определить, являются ли эскалации блокировок основной причиной заблокированных процессов:

...
Шаг 3. Просмотрите трассировку в SQL Server Profiler.

Есть два основных индикатора, которые сообщат вам, связана ли блокировка с эскалацией блокировки.

Сначала вы видите серию событий эскалации блокировок, непосредственно предшествующих событиям отчета о заблокированных процессах. Ниже приведен пример, взятый из трассировки, созданной инструментом Performance Analyzer для Microsoft Dynamics. Это одна вещь, которую нужно искать в трассировке, но это само по себе не означает, что эскалация блокировки вызывает блокировку. ...

и далее

Чтобы убедиться, что блокировка действительно связана с эскалацией блокировки, вам нужно посмотреть подробности отчета о заблокированном процессе. В разделе TextData ищите ресурс ожидания (см. Скриншот ниже). Если waitresource начинается с OBJECT, мы знаем, что заблокированный оператор ожидает блокировки уровня таблицы, чтобы снять его, прежде чем он сможет продолжить. Если waitresource начинается с KEY или PAG вместо OBJECT, то повышение блокировки не включается в этот конкретный блок . Эскалация блокировки всегда увеличивает объем блокировки до OJBECT независимо от того, где она начинается

Решение

(только если вышеуказанные совпадения)

Очевидно, что решение состоит в том, чтобы включить флаг трассировки 1224, который отключит эскалацию блокировки:

Эскалация и блокировка блокировки SQL Server

Если вы видите эти две вещи вместе, то вполне вероятно, что повышение блокировки вызывает блокировку, и вы, вероятно, выиграете от реализации флага трассировки SQL Server 1224.

Флаги трассировки SQL Server для Dynamics AX

Флаг трассировки 1224 отключает эскалацию блокировки в зависимости от количества блокировок. Включение этого флага трассировки может снизить вероятность блокировки из-за повышения блокировки - то, что я видел в ряде реализаций AX. Наиболее распространенным сценарием, когда это становится проблемой, является необходимость выполнения основного планирования в течение дня.

Ответ

В конце концов, это может быть вызвано тем, что эскалация блокировок является основной причиной заблокированных процессов.


Альтернативное решение (узел процесса пуст)

После дальнейшего изучения некоторых заблокированных_процессов можно сделать следующее альтернативное объяснение.

Расширенные события захватывают заблокированные_процессы_reports, которые не связаны ни с какими другими процессами в данный момент.

Ergo: Они должны быть заблокированы по другой причине

Я бы посоветовал вам зафиксировать временные рамки типов ожидания из представления sys.dm_os_wait_stats на вашем SQL Server и сопоставить числа с заблокированным_процессом_reports, который происходит во время ваших измерений. У Пола Рэндалла есть хороший сценарий: пришлите мне статистику ожидания и получите мой совет и 30 дней бесплатного Pluralsight взамен

Скрипты фиксируют текущие счетчики, ждут 23 часа (могут быть изменены), снова собирают текущие счетчики и сравнивают их, чтобы получить 95% лучших типов ожидания. Вы можете попробовать это, скажем, в течение 1 часа и иметь под рукой файл XEL.

Вы можете найти тип ожидания (например, LCK_M_SH, ...), который говорит вам, что ваше хранилище медленно записывается. Или что у вас есть другие накладные расходы (например, CX_PACKET_WAITS,….). Что-то тормозит ваши обновления. Затем вы можете увидеть, относятся ли sys.dm_os_wait_stats к заблокированному_процессу_портов с пустыми узлами.

Существуют случаи, когда заблокированный SPID блокируется тем же SPID:

Столбец заблокированных в таблице sysprocesses заполняется ожидания защелки после установки SQL Server 2000 SP4

Когда SPID ожидает защелки страницы ввода / вывода, вы можете заметить, что столбец заблокирован кратко сообщает о том, что SPID блокируется сам. Такое поведение является побочным эффектом использования защелок для операций ввода-вывода на страницах данных. Когда поток выдает запрос ввода-вывода, SPID, который выдает запрос ввода-вывода, получает блокировку на странице. Все операции ввода-вывода SQL Server 2000 являются асинхронными. Поэтому SPID будет пытаться получить другую защелку на той же странице, если SPID, выдавший запрос ввода-вывода, должен дождаться его завершения. Эта вторая защелка заблокирована первой защелкой. Таким образом, столбец заблокирован сообщает, что SPID блокирует себя. Когда запрос ввода-вывода заканчивается, первая защелка освобождается. Затем второй запрос защелки удовлетворяется.

Альтернативный ответ

Это еще один признак того, что у вас могут быть проблемы с IO. Эти проблемы приводят к «заблокированным процессам», но без соответствующего внешнего SPID. Расширенные события могут не сообщать о процессе / SPID в отдельном узле.

Джон ака hot2use
источник
Я мог бы неправильно это прочитать, но разве эта информация не доказывает, что проблема не в эскалации блокировки? В одном цитируемом разделе говорится "look at the blocked process report details.", и самый верхний XML в этом вопросе - это отчет о заблокированных процессах. Далее в том же цитируемом разделе говорится "If waitresource starts with KEY or PAG instead of OBJECT, then lock escalation isn’t involved in that specific block."и XML-отчет о заблокированном процессе waitresource="KEY: 6:72057..... Таким образом, это означает, что «эскалация блокировки не задействована» здесь.
Соломон Руцкий
Нет, вы НЕ неправильно понимаете это. Раздел, представленный в вопросе, является одной проблемой на этом сервере. Мой ответ - глобальный подход к проблемам, которые могут возникнуть из-за блокирования и эскалации блокировки. Если вы можете исправить некоторые серьезные проблемы (заблокированные_процессы_reports для блокировки уровня OBJECT), небольшие проблемы (заблокированные_процессы_процессы на других уровнях) могут решить сами. Это причина, почему я также добавил второй альтернативный ответ.
Джон aka hot2use