为什么这个 RX-X 锁没有出现在扩展事件中?

For*_*est 13 sql-server locking sql-server-2017

问题

我有一对查询,在可序列化隔离下,会导致 RX-X 锁定。但是,当我使用扩展事件查看锁获取时,RX-X 锁获取从未出现,它只是释放。它从何而来?

再现

这是我的表:

CREATE TABLE dbo.LockTest (
ID int identity,
Junk char(4)
)

CREATE CLUSTERED INDEX CX_LockTest --not unique!
ON dbo.LockTest(ID)

--preload some rows
INSERT dbo.LockTest
VALUES ('data'),('data'),('data')
Run Code Online (Sandbox Code Playgroud)

这是我的问题批次:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRAN

INSERT dbo.LockTest
VALUES ('bleh')

SELECT *
FROM dbo.LockTest
WHERE ID = SCOPE_IDENTITY()

--ROLLBACK
Run Code Online (Sandbox Code Playgroud)

我检查了这个会话持有的锁,并看到了 RX-X:

SELECT resource_type, request_mode, request_status, resource_description
FROM sys.dm_tran_locks
WHERE request_session_id = 72 --change SPID!
Run Code Online (Sandbox Code Playgroud)

dm_tran_locks

但我在lock_acquired和上也有一个扩展事件lock_released。我在适当的 associated_object_id 上过滤它...没有 RX-X。

扩展事件输出

执行回滚后,我看到 RX-X (LAST_MODE) 被释放,即使它从未被获取。

LAST_MODE

我试过的

  • 我查看了扩展事件中的所有锁 - 没有过滤。没有获得 RX-X 锁。

  • 我还尝试了 Profiler:相同的结果(当然,它的名称是正确的……没有“LAST_MODE”)。

  • 我运行 XE 进行锁定升级 - 它不在那里。

  • 没有专门用于转换的 XE,但我能够确认至少 U 到 X 锁的转换被捕获 lock_acquired

同样值得注意的是 RI-N 被收购但从未发布。我现在的假设是,RX-X是一个转换锁,如所描述这里。我的批次中有重叠的键范围锁,看起来它们应该符合转换条件,但 RX-X 锁不在转换表中。

这个锁是从哪里来的,为什么它没有被扩展事件捡到?

Pau*_*ite 12

单行插入获取X对新行的(独占)锁。

所述SELECT获取范围共享,密钥共享的尝试(RangeS-S)锁。

此请求由lock_acquired扩展事件报告为 mode = RS_S

Profiler 事件类Lock:Acquired将其报告为模式 13 ( LCK_M_RS_S)。

请求的模式与in中现有的排他锁模式相结合。不存在范围共享、键独占 ( ) 的组合模式,因此计算的结果是范围独占、键独占 ( ),恰好是模式 15。Lock::CalculateGrantModesqlmin.dllRangeS-XRangeX-X

上面的授权模式计算是在扩展事件由 生成之前执行的lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>。然而,探查器和扩展事件都记录请求的 RangeS-S模式,而不是结果的锁定模式RangeX-X。这与有限的文档相反,它说:

模式 | 国际| 获取锁后的结果模式。

扩展事件的模式列根本没有文档,元数据中的描述是空白的。也许微软自己甚至不确定这种行为。

我经常认为如果锁定事件同时报告请求的结果的模式会更有用,但这不是我们所拥有的。当前的安排使得跟踪和匹配锁获取和释放几乎是不可能的。

可能是报告锁这样一个很好的理由。如果它不能满足你的需求,你可以向 Microsoft 打开一个支持案例,或者创建一个 Azure 反馈项目。


LAST_MODE

神秘LAST_MODE是埃里克·达林( Erik Darling ) 之前评论过的。它是map_key公开的锁定模式列表中的最高值sys.dm_xe_map_values

SELECT
    DXMV.map_key,
    DXMV.map_value
FROM sys.dm_xe_map_values AS DXMV
WHERE 
    DXMV.[name] = N'lock_mode'
ORDER BY
    DXMV.map_key;
Run Code Online (Sandbox Code Playgroud)
SELECT
    DXMV.map_key,
    DXMV.map_value
FROM sys.dm_xe_map_values AS DXMV
WHERE 
    DXMV.[name] = N'lock_mode'
ORDER BY
    DXMV.map_key;
Run Code Online (Sandbox Code Playgroud)

通过 DMV 访问的内存结构(使用sqlmin!CMapValuesTable)从地址 开始存储sqlmin!XeSqlPkg::g_lock_mode。结构中的每个 16 字节条目都包含map_key和 一个指向map_value流 TVF返回的字符串的指针。

字符串的存储完全如上表所示(尽管不是按此顺序)。条目 21 具有map_value“LAST_MODE”而不是预期的“RX_X”似乎是一个错误。Erik Darling 已在 Azure 反馈上报告了该问题