web-dev-qa-db-ja.com

ブロックされたプロセスレポートの空のブロックプロセス

拡張イベントを使用してブロックされたプロセスレポートを収集していますが、いくつかのレポートでは、何らかの理由で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)
2016年6月23日17:45:11 Copyright(c)Microsoft Corporation Enterprise Edition:Core-based Licensing(64-bit)on Windows NT 6.3(Build 14393:)(Hypervisor)

拡張イベントはかなり単純で、ブロックされたプロセスレポートをログに記録するだけです。

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で構成されており、max degree of parallelismが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に関連しています。

現時点では、バックグラウンドで実行されているインデックスやその他のデータベースメンテナンスジョブはありません。

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

これは、その頃の同じリソースのロギングテーブルにあります。 文字数制限のため要点

さらに調査したところ、ブロックプロセスが空のレポートの直前と直後に、ブロックプロセスノードのある同じリソースIDのレポートがあることがわかりました。

<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に投稿されます 最大投稿長のため。

最初に投稿されたデータには両方のセッションIDがなかったため、いくつかの新しいデータが投稿されました githubに再度

接続を含む新しいデータ github

現時点ではこの理論をテストすることはできませんが、 GitHubに投稿された最新のキャプチャデータ に基づいて、<process>ノードが空である理由は、現在実行中のリクエストが必要であることです(属性の多くはsys.dm_exec_requestsではなくsys.dm_exec_sessionsにありますが、現在実行中のリクエストがないと、詳細を報告できません。たとえば、INNER JOINsys.dm_exec_requestsの間でsys.dm_exec_sessionsを実行すると、セッションがアクティブであるがアイドル状態の行が除外されます。現在のリクエストがないため。

最上位のデータセット(monitorLoop値:1748823、1748824、1748825、および1748827)を見ると、次のことがわかります。

  • blocked-processidはいずれの場合も同じです:process2552c1fc28、唯一の属性はwaittime(わかりやすい)。
  • blocking-processノードの属性は、lastbatchstartedlastbatchcompletedの両方の違いを示します
  • blocking-processノードの属性は、spidxactidに同じ値を示します

では、ブロックプロセスのSessionIDとTransactionIDを4つの異なるクエリバッチでどのように同じにすることができるのでしょうか。簡単です。明示的なトランザクションが開始され、これらのバッチが実行されました。また、これらは別々のバッチであるため、送信されるまでの時間があります。その時点では、現在の要求はなく、プロセス情報は表示されません(ただし、セッションとトランザクションはまだそこにあります)。

これについてさらに調査するには、次のT-SQLをSQL Serverエージェントの「Transaction-SQLスクリプト(T-SQL)」ジョブステップに配置し、「データベース」を次のように設定することで、sys.dm_exec_requestsおよびsys.dm_tran_locksから役立つ情報を取得できます。調査中のもの(この場合はIDが6のジョブ)であり、このジョブを10秒ごとに実行するようにスケジュールします。以下のT-SQLは、2つのテーブルが存在しない場合は同じDBに作成し、リクエストがそれ自体をブロックしている場合、またはブロックされている削除または更新オペレーションの場合は、「リクエスト」テーブルにデータを入力します。 。リクエストが見つかった場合、キャプチャを試みます。

  • ブロッキングプロセスのセッションおよび要求情報(この部分では、アクティブな要求があることを想定していないため、少なくともセッション情報を取得するためのRIGHT JOIN
  • ブロックされているプロセスと(うまくいけば)ブロックしているプロセスの接続情報。
  • それらの同じsession_idの現在のロック(ロック情報は100%正確であると保証されていないことに注意してくださいその情報は実行中の2つのステートメント間の時間で変化する可能性がある;それでも、情報は、キャプチャする価値があるほど頻繁に十分です)。 このセクションは現在コメント化されています。

SQL ServerエージェントT-SQLジョブステップ:

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

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

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

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

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

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

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

1つのクエリタブを開いて次を実行することで、これを再現できるはずです。

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

次に、2番目のクエリタブを開き、次を実行します。

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

追伸それを述べただけで、意味をなさない唯一のことは、リクエストとセッション情報– dbo.tmpBlockingResearch_Requests –がブロッキングセッションの行をまだ含むことはないということです。それでも、両方のSessionIDのロックを取得したので、テーブル変数にはブロッキングセッションIDが含まれています。これは、クライアントからの「接続」が閉じられた後もトランザクションが開いたままであることが許可されているが、接続プーリングが原因で接続が維持されているというシナリオを示している可能性があります。

6
Solomon Rutzky

ブロックされたトランザクションは、ロックのエスカレーションのために発生する可能性があります。

これは、Microsoftサポートの記事で説明されています。

SQL Serverのロックのエスカレーションによって引き起こされるブロッキングの問題を解決する方法

...
ロックのエスカレーションは、ほとんどのブロッキングの問題を引き起こしません。ブロックの問題が発生する前後にロックのエスカレーションが発生しているかどうかを確認するには、Lock:Escalationイベントを含むSQLプロファイラートレースを開始します。 Lock:Escalationイベントが表示されない場合は、サーバーでロックのエスカレーションが発生していないため、この記事の情報は該当しません。

ロックのエスカレーションが発生している場合は、エスカレートされたテーブルロックが他のユーザーをブロックしていることを確認します
...

拡張イベント(物理ファイル)でlock escalationblocked processイベントの前に発生したイベントを確認します。

説明する

詳細については、Microsoftブログの記事をご覧ください。

SQL Serverロックのエスカレーションとブロック

...
ステップ2:ロックのエスカレーションとブロックされたプロセスのレポートイベントを収集します。

ロックのエスカレーションとブロックされたプロセスレポートのイベントは、SQL Serverによって自動的にキャプチャされません。これらのイベントが発生しているかどうかを確認するには、SQL Serverにそれらを記録するように指示する必要があります。私たちのチームは、Microsoft Dynamicsツールのパフォーマンスアナライザーを使用して、その情報を収集します。ツールの詳細と、ツールを使用してブロックの詳細を収集する方法については、Rod Hansenによるこの投稿を確認してください。 SQL Server Profilerを使用したいだけの場合、収集する必要があるイベントを以下に示します。..

ロックのエスカレーションとブロックされたプロセスをキャプチャした後、ロックのエスカレーションがブロックされたプロセスの根本的な原因であるかどうかを判断する必要があります。

...
ステップ3:SQL Serverプロファイラーでトレースを確認します。

ブロッキングがロックのエスカレーションに関連しているかどうかを示す2つの主要なインジケーターがあります。

まず、ブロックされたプロセスレポートイベントの直前に一連のロックエスカレーションイベントが表示されます。以下は、Microsoft Dynamicsツールのパフォーマンスアナライザーによって生成されたトレースから取得した例です。これはトレースで調べる必要がある1つのことですが、これだけでは、ロックのエスカレーションがブロックの原因になっているわけではありません。 ...

そしてさらに

ブロックが実際にロックのエスカレーションに関連していることを確認するには、ブロックされたプロセスレポートの詳細を確認する必要があります。 TextDataセクションでwaitresourceを探します(下のスクリーンショットを参照)。 waitresourceがOBJECTで始まる場合、ブロックされたステートメントは、テーブルレベルのロックが解放されるのを待ってから、処理を続行できます。 waitresourceが[〜#〜] key [〜#〜]またはOBJECTの代わりに[〜#〜] pag [〜#〜]で始まる場合、ロックのエスカレーションはその特定のブロックに関与していません。ロックのエスカレーションは、開始位置に関係なく、常にOJBECTへのロックの範囲を拡大します

解決

(上記のものが一致する場合のみ)

解決策は、トレースエスカレーションをオフにするトレースフラグ1224をオンにすることです。

SQL Serverロックのエスカレーションとブロック

これら2つを同時に見た場合、ロックのエスカレーションがブロックを引き起こしていることはかなり良いことであり、SQL Serverトレースフラグ1224を実装することでメリットが得られるでしょう。

Dynamics AXのSQL Serverトレースフラグ

トレースフラグ1224は、ロックの数に基づいてロックのエスカレーションを無効にします。このトレースフラグを有効にすると、ロックのエスカレーションによるブロックの可能性を減らすことができます。これは、多くのAX実装で見られたものです。これが問題になる最も一般的なシナリオは、日中にマスタープランニングを実行する必要がある場合です。

回答

最終的に、ロックのエスカレーションがブロックされたプロセスの根本的な原因である可能性があります。


代替ソリューション(プロセスノードが空)

blocked_process_reportsをさらに調査した後、次の代替説明を行うことができます。

拡張イベントは、その時点で他のプロセスとは無関係のblocked_process_reportsをキャプチャしています。

エルゴ:別の理由でブロックする必要があります

SQL Serverのsys.dm_os_wait_statsビューから待機タイプの時間枠をキャプチャし、数値を測定中に発生したblocked_process_reportsと関連付けることをお勧めします。 Paul Randallは良いスクリプトを持っています: 私にあなたの待機統計を送って、私のアドバイスと30日間の無料Pluralsightをお返しに

スクリプトは現在のカウンターをキャプチャし、23時間待機し(変更可能)、現在のカウンターを再度キャプチャして比較し、上位95%の待機タイプを取得します。これを1時間試して、XELファイルを手元に置いてください。

ストレージの書き込みが遅いことを通知する待機タイプ(LCK_M_SHなど)が見つかる場合があります。または、その他のオーバーヘッドがあること(CX_PACKET_WAITSなど)。何かがアップデートを遅くしています。次に、sys.dm_os_wait_statsがノードが空のblocked_process_reportsに関連しているかどうかを確認できます。

ブロックされたSPIDが同じSPIDによってブロックされている場合があります。

SQL Server 2000 SP4をインストールした後、sysprocessesテーブルのブロックされた列にラッチ待機用の値が入力されます

SPIDがI/Oページラッチを待機しているとき、ブロックされた列がSPID自体をブロックしていることを簡単に報告することがあります。この動作は、ラッチがデータページのI/O操作に使用される方法の副作用です。スレッドがI/O要求を発行すると、I/O要求を発行するSPIDがページのラッチを取得します。 SQL Server 2000のすべてのI/O操作は非同期です。したがって、I/O要求を発行したSPIDが要求が完了するまで待機する必要がある場合、SPIDは同じページで別のラッチを取得しようとします。この2番目のラッチは、最初のラッチによってブロックされます。したがって、blocked列は、SPIDがそれ自体をブロックしていることを報告します。 I/O要求が完了すると、最初のラッチが解放されます。次に、2番目のラッチ要求が許可されます。

代替回答

これは、IO問題が発生している可能性があることを示しています。これらの問題により、「ブロックされたプロセス」が発生しますが、関連する外部SPIDはありません。拡張イベントは、別のノードのプロセス/ SPIDを報​​告しない場合があります。

4