阻塞进程报告中的空阻塞进程

Tom*_*m V 28 sql-server profiler extended-events sql-server-2012 blocking

我正在使用扩展事件收集阻塞的进程报告,并且由于某些原因,在某些报告中该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>
Run Code Online (Sandbox Code Playgroud)

此 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
Run Code Online (Sandbox Code Playgroud)

不涉及分区,这是表定义:

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
Run Code Online (Sandbox Code Playgroud)

整个数据库中的任何表都没有定义触发器或外键。

确切的 SQL Server 版本是:

Microsoft SQL Server 2012 (SP3-CU4) (KB3165264) - 11.0.6540.0 (X64)
2016 年 6 月 23 日 17:45:11 版权所有 (c) Microsoft Corporation Enterprise Edition:Windows NT 6.3 上的基于内核的许可(64 位)(内部版本 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
Run Code Online (Sandbox Code Playgroud)

数据库在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 |
+------------------------------------+-------+
Run Code Online (Sandbox Code Playgroud)

我运行了一段时间的服务器端跟踪,并且在跟踪文件中获得了与使用扩展事件相同的空节点。
此被阻止的进程报告是使用另一台同样运行 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>
Run Code Online (Sandbox Code Playgroud)

有人对这些报道有解释吗?什么阻止了查询?

如果我在锁早已消失后查看报告,有没有办法找出发生了什么?

添加可能有用的一件事是这些查询是通过sp_cursorpreparesp_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>
Run Code Online (Sandbox Code Playgroud)

这可以在当时相同资源的日志记录表中找到:Gist 因为字符限制

进一步调查显示,在报告具有空阻塞进程之前和之后,我有关于具有阻塞进程节点的相同资源 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>
Run Code Online (Sandbox Code Playgroud)

使用srutzky提供的新脚本收集了新数据。 由于最大帖子长度,它发布在github上

由于最初发布的数据没有两个会话ID,因此一些新数据已再次发布在github上

新数据,包括github 上的连接

Sol*_*zky 6

我目前无法测试这个理论,但是根据发布到 GitHub 的最新捕获数据,我会说<process>节点为空的原因是它需要当前正在运行的请求(许多属性都在sys.dm_exec_requests并且不在sys.dm_exec_sessions) 并且没有当前正在运行的请求,它无法报告任何详细信息,类似于如何执行INNER JOINbetween sys.dm_exec_requestssys.dm_exec_sessions将排除会话处于活动状态但由于当前没有请求而空闲的行。

查看顶部数据集(monitorLoop值:1748823、1748824、1748825 和 1748827),我们可以看到以下内容:

  • 所述idblocked-process在每种情况下是相同的:process2552c1fc28,那就是不同的唯一属性是waittime(理解)。
  • blocking-process节点的属性在两者lastbatchstartedlastbatchcompleted
  • blocking-process节点的属性显示相同的值spidxactid

那么,在4个不同的查询批次中,阻塞进程的SessionID和TransactionID怎么可能相同呢?很简单,一个显式事务被启动,然后这些批次被执行。并且因为这些是单独的批次,它们被提交之间有时间,此时没有当前请求,因此没有进程信息显示(但会话和事务仍然存在)。

为了做更多的研究,这一点,你可以捕捉有用的信息sys.dm_exec_requests,并sys.dm_tran_locks通过将下面的T-SQL在SQL Server代理“交易-SQL脚本(T-SQL)”作业步骤,设置“数据库”是您正在研究的一个(在本例中是 ID 为 6 的那个),并安排此作业每 10 秒运行一次。如果它们不存在,下面的 T-SQL 将在同一个数据库中创建两个表,然后如果任何请求本身阻塞,或者它是被阻塞的删除或更新操作,则将填充“请求”表. 如果找到任何请求,它将尝试捕获:

  • 关于阻塞过程的会话和请求信息(这部分不假设有一个活动的请求,因此RIGHT JOIN至少要获取会话信息)
  • 被阻止和(希望)阻止进程的连接信息。
  • 相同 session_id 的当前锁(请记住,不能保证锁信息是100% 准确的,因为该信息可能会在这两个语句执行之间的时间内发生变化;不过,该信息足够频繁,足以值得捕捉)。 此部分目前已被注释掉。

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
                                     );
 */
Run Code Online (Sandbox Code Playgroud)

我认为您应该能够通过打开一个查询选项卡并执行以下操作来重现这一点:

CREATE TABLE dbo.tmp (Col1 INT);
BEGIN TRAN;
INSERT INTO dbo.tmp (Col1) VALUES (1);
Run Code Online (Sandbox Code Playgroud)

然后,打开第二个查询选项卡并执行以下操作:

UPDATE dbo.tmp
SET    Col1 = 2
WHERE  Col1 = 1;
Run Code Online (Sandbox Code Playgroud)

PS 只是说一下,唯一没有意义的是请求和会话信息 – dbo.tmpBlockingResearch_Requests– 仍然从不包含阻塞会话的行。但是我知道表变量中包含阻塞会话 ID,因为它确实为两个 SessionID 拉入了锁。这可能指向这样一种情况:在来自客户端的“连接”关闭后,允许事务保持打开状态,但由于连接池,连接仍然保持。


Joh*_* N. 4

由于锁升级,可能会出现事务被阻止的情况。

\n\n

Microsoft 支持文章中对此进行了解释:

\n\n

如何解决 SQL Server 中由锁升级引起的阻塞问题

\n\n
\n

...
\n 锁升级不会导致大多数阻塞问题。要确定在遇到阻塞问题时是否发生锁升级,请启动包含 Lock:Escalation 事件的 SQL Profiler 跟踪。如果您没有看到任何 Lock:Escalation 事件,则表明您的服务器上没有发生锁升级,并且本文中的信息不适用于您的情况。

\n\n

如果发生锁升级,请验证升级的表锁是否正在阻止其他用户
\n ...

\n
\n\n

检查扩展事件(物理文件)中是否有在阻塞进程事件之前发生的锁升级事件。

\n\n

解释

\n\n

有一篇 Microsoft 博客文章对此进行了更详细的介绍:

\n\n

SQL Server 锁升级和阻塞

\n\n
\n

...
\n 第 2 步:收集锁升级和阻塞进程报告事件。

\n\n

SQL Server 不会自动捕获锁升级和阻塞进程报告事件。为了知道这些事件是否正在发生,我们需要告诉 SQL Server 记录它们。我们的团队使用 Microsoft Dynamics 性能分析器工具来收集该信息。查看 Rod Hansen 的这篇文章,了解有关该工具以及如何使用它收集阻止详细信息的更多信息。如果您只想使用 SQL Server Profiler,则需要收集的事件如下所示:\n ...

\n
\n\n

捕获锁升级和阻塞进程后,您必须确定锁升级是否是阻塞进程的根本原因:

\n\n
\n

...
\n 步骤 3:在 SQL Server Profiler 中查看跟踪。

\n\n

有两个主要指标可以告诉您阻塞是否与锁升级有关。

\n\n

首先,您会在阻塞进程报告事件之前看到一系列锁升级事件。下面是取自 Microsoft Dynamics 性能分析器工具生成的跟踪的示例。这是在跟踪中寻找的一件事,但仅此一点并不意味着锁升级导致了阻塞。\n ...

\n
\n\n

并进一步

\n\n
\n

要验证阻塞实际上与锁升级相关,您需要查看阻塞进程报告详细信息。在 TextData 部分中查找 waitresource(请参见下面的屏幕截图)。如果 waitresource 以 OBJECT 开头,我们知道被阻塞的语句正在等待表级锁被释放,然后才能继续。如果 waitresource 以KEYPAG而不是 OBJECT 开头,则该特定块中不涉及\xe2\x80\x99t 锁升级。锁升级总是会增加 OJBECT 的锁范围,无论它从哪里开始

\n
\n\n

解决方案

\n\n

(仅当上述匹配时)

\n\n

显然,解决方案是打开跟踪标志 1224,这将关闭锁升级:

\n\n

SQL Server 锁升级和阻塞

\n\n
\n

如果您同时看到这两件事,则可以肯定是锁升级导致了阻塞,并且您可能会从实施 SQL Server 跟踪标志 1224 中受益。

\n
\n\n

Dynamics AX 的 SQL Server 跟踪标志

\n\n
\n

跟踪标志 1224 根据锁的数量禁用锁升级。启用此跟踪标志可以降低由于锁升级而导致阻塞的可能性 - 我在许多 AX 实现中都看到过这种情况。出现此问题的最常见情况是需要在白天运行主计划时

\n
\n\n

回答

\n\n

最后,锁升级可能是阻塞进程的根本原因。

\n\n
\n\n

替代解决方案(进程节点为空)

\n\n

在进一步调查一些被阻止的进程报告后,可以做出以下替代解释。

\n\n

扩展事件正在捕获与当时任何其他进程无关的阻塞进程报告。

\n\n

因此:他们必须因为不同的原因而被阻止

\n\n

我建议您从 SQL Server 上的 sys.dm_os_wait_stats 视图捕获等待类型的时间范围,并将这些数字与测量期间发生的 Blocked_process_reports 相关联。Paul Randall 有一个很好的脚本: 将您的等待统计数据发送给我并获取我的建议和 30 天免费 Pluralsight 作为回报

\n\n

脚本捕获当前计数器,等待 23 小时(可以修改),再次重新捕获当前计数器并比较它们,以给出前 95% 的等待类型。您可以尝试此操作(例如 1 小时)并准备好 XEL 文件。

\n\n

您可能会发现等待类型(例如 LCK_M_SH、\xe2\x80\xa6)告诉您存储写入速度很慢。或者您还有其他一些开销(例如 CX_PACKET_WAITS、\xe2\x80\xa6)。有些东西正在减慢您的更新速度。然后,您可以查看 sys.dm_os_wait_stats 是否与具有空节点的Blocked_process_reports 相关。

\n\n

在某些情况下,阻塞的 SPID 会被同一 SPID 阻塞:

\n\n

安装 SQL Server 2000 SP4 后,sysprocesses 表中的阻塞列将填充闩锁等待

\n\n
\n

当 SPID 等待 I/O 页锁存器时,您可能会注意到阻塞列简要报告 SPID 本身正在阻塞。此行为是锁存器用于数据页上的 I/O 操作的方式的副作用。当线程发出 I/O 请求时,发出 I/O 请求的 SPID 会获取该页上的锁存器。所有 SQL Server 2000 I/O 操作都是异步的。因此,如果发出 I/O 请求的 SPID 必须等待请求完成,则 SPID 将尝试获取同一页上的另一个锁存器。该第二锁存器被第一锁存器阻挡。因此,阻塞列报告 SPID 本身正在阻塞。当 I/O 请求完成时,第一个锁存器被释放。然后,第二个锁存请求被准许。

\n
\n\n

替代答案

\n\n

这进一步表明您可能遇到 IO 问题。这些问题会导致“进程被阻止”,但没有相关的外部 SPID。扩展事件可能不会报告单独节点中的进程/SPID。

\n