Порожній процес блокування у звіті про заблокований процес


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 Авторські права (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 Read Comted Snapshot, а максимальна ступінь паралелізму встановлена ​​на 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

Відповіді:


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), ми можемо побачити наступне:

  • the idof 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 в агенті SQL Server "Сценарій транзакцій-SQL (T-SQL)" Крок роботи, встановивши "База даних" бути той, який ви досліджуєте (в даному випадку це той, який має ідентифікатор 6), і плануєте цю роботу виконувати кожні 10 секунд. T-SQL нижче створить дві таблиці в тій самій БД, якщо вони не існують, а потім заповнить таблицю "Запити", якщо будь-який запит блокує сам себе, або якщо операція "Видалення або оновлення" блокується. . Якщо будь-які запити будуть знайдені, він спробує захопити:

  • Інформація про сеанс та запит щодо процесу блокування (ця частина не передбачає активного запиту, отже, RIGHT JOINщоб принаймні отримати інформацію про сеанс)
  • Інформація про з'єднання для блокованих та (сподіваємось) блокуючих процесів.
  • поточні блокування для тих самих session_id (лише майте на увазі, що інформація про блокування не гарантована на 100% точністю, оскільки ця інформація може змінюватися за час між цими двома операторами, які виконуються; все-таки інформація є достатньо частою, щоб досить варто захопити). Цей розділ наразі прокоментовано.

Крок завдання агента 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- все ще ніколи не містить рядків для блокуючого сеансу. Але я знаю, що змінна таблиці містить ідентифікатор сеансу блокування, оскільки вона втягувала блоки в обох SessionID. Це може вказувати на сценарій, коли трансакції дозволяється залишатись відкритими після того, як "з'єднання" від клієнта закрите, але з'єднання все ще підтримується завдяки Об'єднанню.


@TomV Я переглянув новітні дані досліджень і маю досить ґрунтовну теорію. Відповідно я оновив свою відповідь, включаючи додавання розділу до моїх дослідницьких запитів, тому будь ласка, замініть SQL крок завдання на нові запити тут (я також прокоментував запит "блокування", оскільки нам зараз справді не потрібні ці дані, і це багато даних). Я пропоную обрізати / відкинути існуючі дослідницькі таблиці, щоб почати все з нуля.
Соломон Руцький

@TomV Добре. І я оновив запит на запит на оновлення, щоб він був ОНОВЛЕНО, а не ВИБІР, тож у будь-якому випадку він повинен бути більш репрезентативним для вашої ситуації. У кінці я також додав примітку про відсутні рядки в таблиці запитів. Сподіваємось, нова таблиця Connections принаймні підтвердить продовження існування блокуючого SessionID. (PS, я почав прибирати свої коментарі вище).
Соломон Руцький

Ваша робота активна. Мені потрібно знайти час, щоб перевірити репроміс і проаналізувати його на наступному тижні
Том V - Команда Моніка

Привіт Соломоне. 2 нові приклади були розміщені на github. На жаль, я не зміг запустити порожній процес блокування BPR за допомогою наданого випадку запиту.
Том V - Команда Моніки

Подивився дуже швидко, оскільки у мене не так багато часу. Схоже, інформація про з’єднання показує, що ідентифікатор блокування сеансу все ще активний, але його немає в таблиці сеансів. Я можу це перевірити пізніше, але я впевнений, що вказує об'єднання з'єднань (з'єднання все-таки є), а з'єднання закрите між командами, але транзакція чітко відкрита (оскільки transak_id завжди такий, як ми бачили минулого разу). Пізніше подивимось пізніше ..
Соломон Руцький

4

Блоковані транзакції можуть статися через ескалації блокування.

Це пояснено у статті підтримки Microsoft:

Як вирішити проблеми блокування, які викликані ескалацією блокування в SQL Server

...
Ескалація блокування не викликає більшості проблем із блокуванням. Щоб визначити, чи відбувається ескалація блокування приблизно в той час, коли виникають проблеми з блокуванням, почніть слід SQL Profiler, який включає в себе подію Lock: Escalation. Якщо ви не бачите жодних подій блокування: ескалація, ескалація блокування не відбувається на вашому сервері, і інформація в цій статті не стосується вашої ситуації.

Якщо відбувається ескалація блокування, переконайтеся, що блокування ескальованої таблиці блокує інших користувачів
...

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

Пояснення

Існує стаття в блозі Microsoft, яка детальніше описується:

Ескалація та блокування блокування SQL Server

...
Крок 2: Зберіть ескалацію блокування та звітування про заблоковані процеси.

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

Після того як ви захопили ескалації блокування та заблоковані процеси, ви повинні визначити, чи є ескалації блокування першопричиною заблокованих процесів:

...
Крок 3: Перегляньте слід у програмі SQL Server Profiler.

Є два основні індикатори, які підкажуть, чи блокування пов'язане з ескалацією блокування.

По-перше, ви бачите серію подій ескалації блокування безпосередньо перед блокованими подіями звіту про процес. Нижче наводиться приклад, взятий із сліду, створеного аналізатором продуктивності для інструмента Microsoft Dynamics. Це одне, що потрібно шукати у сліді, але це одне не означає, що ескалація блокування викликає блокування. ...

і далі

Щоб переконатися, що блокування насправді пов'язане з ескалацією блокування, потрібно переглянути деталі звіту про заблокований процес. У розділі TextData знайдіть ресурс очікування (див. Скріншот нижче). Якщо ресурс очікування починається з OBJECT, ми знаємо, що заблокований оператор очікує на блокування рівня таблиці, щоб вивільнити його, перш ніж він може продовжуватися. Якщо ресурс очікування починається з KEY або PAG замість OBJECT, ескалація блокування не бере участь у цьому конкретному блоці . Ескалація блокування завжди збільшуватиме обсяг блокування до OJBECT незалежно від місця його запуску

Рішення

(тільки якщо вищезгадані збіги)

Мабуть, рішення увімкнути прапор 1224 сліду, який вимкне ескалацію блокування:

Ескалація та блокування блокування SQL Server

Якщо ви бачите ці дві речі разом, досить непогано зробити ставку, що ескалація блокування викликає блокування, і ви, ймовірно, отримаєте користь від реалізації прапора сліду 1224 SQL Server.

Прапори слідів SQL Server для Dynamics AX

Прапор сліду 1224 вимикає ескалацію блокування на основі кількості блокувань. Увімкнення цього прапора трассування може зменшити ймовірність блокування через ескалацію блокування - що я бачив у ряді реалізацій AX. Найпоширенішим сценарієм, коли це стає проблемою, є те, коли існує потреба у виконанні генерального планування протягом дня

Відповідь

Зрештою, можливо, що ескалація блокування є першопричиною заблокованих процесів.


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

Після подальшого дослідження деяких заблокованих_процесів_звітів можна зробити наступне альтернативне пояснення.

Розширені події фіксують блоковані_процессорні звіти, які не пов'язані з будь-якими іншими процесами на той час.

Ergo: Вони повинні бути заблоковані з іншої причини

Я б запропонував вам зафіксувати часовий діапазон типів очікування з подання sys.dm_os_wait_stats на вашому SQL сервері та співвіднести числа з блокованими_процессорами звітів, які відбуваються під час вимірювань. Пол Рендалл має хороший сценарій: надішліть мені свою статистику очікування та отримайте мою пораду та 30 днів безкоштовного плюралізму натомість

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

Можливо, ви знайдете тип очікування (наприклад, LCK_M_SH, ...), який повідомляє вам про те, що ваш запам’ятовується повільно. Або що у вас є якісь інші накладні витрати (наприклад, CX_PACKET_WAITS,….). Щось уповільнює ваші оновлення. Потім можна побачити, чи sys.dm_os_wait_stats відноситься до заблокованих_процесів_звітів із порожніми вузлами.

Є випадки, коли заблокований SPID блокується тим самим SPID:

Заблокований стовпець у таблиці sysprocess заповнюється для засувки після встановлення SQL Server 2000 SP4

Коли SPID чекає на засувку сторінки вводу / виводу, ви можете помітити, що заблокований стовпець коротко повідомляє про те, що SPID блокується сам. Така поведінка є побічним ефектом від способу використання засувок для операцій вводу / виводу на сторінках даних. Коли потік видає запит вводу / виводу, SPID, який видає запит вводу / виводу, отримує засувку на сторінці. Усі операції вводу / виводу SQL Server 2000 є асинхронними. Тому SPID спробує придбати ще одну засувку на тій же сторінці, якщо SPID, який видав запит вводу / виводу, повинен дочекатися завершення запиту. Ця друга засувка блокується першою засувкою. Тому заблокований стовпець повідомляє, що SPID блокує себе. Коли запит вводу / виводу закінчується, перша засувка звільняється. Потім надається другий запит засувки.

Чергова відповідь

Це ще одне свідчення того, що у вас можуть виникнути проблеми з IO. Ці проблеми призводять до "заблокованих процесів", але без відповідного іноземного SPID. Розширені події можуть не повідомляти про процес / SPID в окремому вузлі.


Я можу це неправильно прочитати, але чи не ця інформація підтверджує, що проблема не є ескалацією блокування? В одному з цитованих розділів йдеться про те "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..... Це означає, що "ескалація блокування не задіяна" тут.
Соломон Руцький

Ні, ви НЕ неправильно читаєте це. Розділ, який надається у запитанні, - це одне питання на цьому сервері. Моя відповідь - це глобальний підхід до питань, які можуть виникнути через блокування та ескалацію блокування. Якщо ви зможете виправити деякі основні проблеми (заблокований_процессорний звіт для блокування рівня OBJECT), то менші проблеми (заблокований_процессорний звіт на інших рівнях) можуть вирішити самі. Це причина, чому я також додав другу альтернативну відповідь.
Джон aka hot2use
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.