查找先前的语句或在阻塞情况下持有锁

Zik*_*ato 7 monitoring sql-server blocking sql-server-2019

我正在使用 XEblocked_process_report 来检测和分析阻塞。
但由于这是一个时间点情况,我只能看到当前正在运行的阻塞领导者的语句以及被阻塞会话试图获取的不兼容锁。

因此,如果阻塞领导者在一个事务中有多个批次/语句,我无法找出之前的哪个语句导致阻塞。

重现脚本

/* Set up tables */
CREATE TABLE dbo.FirstQuery (Id int PRIMARY KEY)
CREATE TABLE dbo.SecondQuery (Id int PRIMARY KEY)

INSERT INTO dbo.FirstQuery (Id)
OUTPUT Inserted.Id INTO dbo.SecondQuery ( Id )
VALUES (1), (2), (3)

/* set up the blocked process event */

EXEC sys.sp_configure
        @configname = 'blocked process threshold (s)' -- varchar(35)
      , @configvalue = 10 -- int
    
RECONFIGURE 

CREATE EVENT SESSION [blocked_process_report] ON SERVER 
ADD EVENT sqlserver.blocked_process_report
(
    ACTION(sqlserver.session_id,sqlserver.sql_text,sqlserver.tsql_stack)
)
GO
ALTER EVENT SESSION [blocked_process_report] ON SERVER STATE = START

/* Session 1 - run first and don't commit or rollback */
BEGIN TRANSACTION
    DELETE FROM dbo.FirstQuery
GO
    DELETE FROM dbo.SecondQuery
-- ROLLBACK

/* Session 2 - run second */
BEGIN TRANSACTION
    DELETE FROM dbo.FirstQuery

Run Code Online (Sandbox Code Playgroud)

阻塞进程报告

<blocked-process-report monitorLoop="3963">
    <blocked-process>
        <process
            id="process22254469468"
            taskpriority="0"
            logused="0"
            waitresource="KEY: 11:72057594047299584 (8194443284a0)"
            waittime="21867"
            ownerId="715194"
            transactionname="user_transaction"
            lasttranstarted="2022-09-22T11:36:27.260"
            XDES="0x222681a0470" lockMode="U"
            schedulerid="15"
            kpid="13744"
            status="suspended"
            spid="125"
            sbid="0"
            ecid="0"
            priority="0"
            trancount="3"
            lastbatchstarted="2022-09-22T11:38:37.947"
            lastbatchcompleted="2022-09-22T11:38:37.947"
            lastattention="2022-09-22T11:38:08.630"
            clientapp="Microsoft SQL Server Management Studio - Query"
            hostname="MyHost"
            hostpid="27992"
            loginname="MyHost\MyLogin"
            isolationlevel="read committed (2)"
            xactid="715194"
            currentdb="11"
            currentdbname="Rubbish"
            lockTimeout="4294967295"
            clientoption1="671090784"
            clientoption2="390200"
        >
            <executionStack>
                <frame line="3" stmtstart="50" stmtend="100" sqlhandle="0x020000007620ac3a2dda99a1c6f6f97305d90262cac2e4080000000000000000000000000000000000000000" />
            </executionStack>
            <inputbuf>
   
   BEGIN TRANSACTION
       DELETE FROM dbo.FirstQuery   </inputbuf>
        </process>
    </blocked-process>
    <blocking-process>
        <process
            status="sleeping"
            spid="121"
            sbid="0"
            ecid="0"
            priority="0"
            trancount="1"
            lastbatchstarted="2022-09-22T11:38:35.193"
            lastbatchcompleted="2022-09-22T11:38:35.193"
            lastattention="1900-01-01T00:00:00.193"
            clientapp="Microsoft SQL Server Management Studio - Query"
            hostname="MyHost"
            hostpid="27992"
            loginname="MyHost\MyLogin"
            isolationlevel="read committed (2)"
            xactid="717574"
            currentdb="11"
            currentdbname="Rubbish"
            lockTimeout="4294967295"
            clientoption1="671090784"
            clientoption2="390200"
        >
            <executionStack />
            <inputbuf>
       DELETE FROM dbo.SecondQuery
   -- ROLLBACK   </inputbuf>
        </process>
    </blocking-process>
</blocked-process-report>
Run Code Online (Sandbox Code Playgroud)

我只能在输入缓冲区中看到当前正在运行的批处理。

我可以在 中找到持有的锁信息sys.dm_tran_locks,但如果阻塞时间很短,我将无法及时捕获它。

; -- Previous statement must be properly terminated 
WITH LockInfo
AS
(
    SELECT
        dtl.request_session_id
      , dtl.resource_type
      , dtl.resource_description
      , dtl.resource_associated_entity_id
      , dtl.request_mode
      , dtl.request_status
    FROM 
        sys.dm_tran_locks AS dtl
)
SELECT 
    *
FROM LockInfo AS blcked
JOIN LockInfo AS blcker
    ON blcker.request_session_id = 121 /* blocker session ID */
    AND blcker.resource_type = blcked.resource_type
    AND blcker.resource_description = blcked.resource_description
    AND blcker.resource_associated_entity_id = blcked.resource_associated_entity_id
WHERE 
    blcked.request_session_id = 125 /* blocked session ID */ 
    AND blcked.request_status = N'WAIT'
Run Code Online (Sandbox Code Playgroud)

是否有任何自动且有效的方法来查找哪个语句导致阻塞以及哪些锁被持有?

我希望找到任何可以帮助我跟踪会话 1 中早期阻止程序的内容(在本例中,DELETE FROM dbo.FirstQuery在代码库中或设置额外的监控)。

  • TSQL 堆栈
  • 查询哈希
  • ObjectId(如果是过程的一部分)
  • sql_文本

我大概可以从语句中推断出持有的锁。