问题
我有一对查询,在可序列化的隔离下,会导致 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')
这是我的问题批次:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
INSERT dbo.LockTest
VALUES ('bleh')
SELECT *
FROM dbo.LockTest
WHERE ID = SCOPE_IDENTITY()
--ROLLBACK
我检查了这个会话持有的锁,并查看了 RX-X:
SELECT resource_type, request_mode, request_status, resource_description
FROM sys.dm_tran_locks
WHERE request_session_id = 72 --change SPID!
lock_acquired
但我在和上也有一个扩展事件lock_released
。我在适当的 associated_object_id 上对其进行过滤……没有 RX-X。
执行回滚后,我看到 RX-X (LAST_MODE) 已释放,即使它从未被获取。
我试过的
我查看了扩展事件中的所有锁 - 没有过滤。未获得 RX-X 锁。
我也尝试了 Profiler: 相同的结果(当然除了它的名字是正确的......没有“LAST_MODE”)。
我运行 XE 进行锁定升级 - 它不存在。
没有专门用于转换的 XE,但我能够确认至少 U 到 X 锁定转换是由
lock_acquired
另外值得注意的是被收购但从未发布的 RI-N。我目前的假设是 RX-X 是转换锁,如此处所述。我的批次中有重叠的键范围锁,看起来它们应该有资格进行转换,但 RX-X 锁不在转换表中。
这个锁是从哪里来的,为什么不被扩展事件拾取?
单行插入获取
X
新行上的(独占)锁。SELECT
尝试获取范围共享的密钥共享 ( )RangeS-S
锁。此请求由
lock_acquired
扩展事件报告为 mode =RS_S
。Profiler 事件类将其报告
Lock:Acquired
为模式 13 (LCK_M_RS_S
)。请求的模式与 in中现有的独占锁模式相结合。没有范围共享,键独占()的组合模式,因此计算的结果是范围独占,键独占(),恰好是模式15。
Lock::CalculateGrantMode
sqlmin.dll
RangeS-X
RangeX-X
上面的授权模式计算是在扩展事件生成之前执行的
lck_ProduceExtendedEvent<XeSqlPkg::lock_acquired>
。尽管如此,Profiler 和 Extended Events 都会记录请求RangeS-S
的模式,而不是生成的锁定模式RangeX-X
。这与有限的文档相反,它说:扩展事件的模式栏根本没有文档,元数据中的描述是空白的。也许微软自己甚至不确定这种行为。
我经常认为如果锁定事件同时报告请求模式和结果模式会更有用,但这不是我们所拥有的。当前的安排使得几乎不可能跟踪和匹配锁的获取和释放。
以这种方式报告锁可能有充分的理由。如果它不能满足你的需求,你可以向 Microsoft 开一个支持案例,或者创建一个 Azure 反馈项。
LAST_MODE
神秘
LAST_MODE
是埃里克·达林(Erik Darling)以前说过的。它是map_key
公开的锁定模式列表中的最大值sys.dm_xe_map_values
:通过 DMV 访问的内存结构(使用
sqlmin!CMapValuesTable
)存储在地址 开始sqlmin!XeSqlPkg::g_lock_mode
。结构中的每个 16 字节条目都包含和指向流 TVFmap_key
返回的字符串的指针。map_value
字符串完全按照上表所示存储(尽管不是按该顺序)。
map_value
条目 21 具有“LAST_MODE”而不是预期的“RX_X”似乎是一个错误。Erik Darling在 Azure 反馈上报告了该问题。