您的测试场景中的第一个问题是该表在firstname
. 第二个是桌子是空的。
从BOL 中的键范围锁定
在发生键范围锁定之前,必须满足以下条件:
没有合适的索引来RangeS-S
锁定,因此为了保证可序列化语义,SQL Server 需要锁定整个表。
如果您尝试在第一个名称列的表上添加聚集索引,如下所示并重复实验...
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
……你会发现你还是被屏蔽了!
尽管现在存在一个合适的索引并且执行计划显示它被寻找以满足查询。
您可以通过运行以下命令来了解原因
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
SELECT *
FROM dummy
WHERE firstname = 'abc'
SELECT resource_type,
resource_description,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
COMMIT
退货
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server 不仅仅对您在查询中指定的范围进行范围锁定。
对于唯一索引上的相等谓词,如果有匹配的键,它将只采用常规锁,而不是任何类型的范围锁。
对于非唯一搜索谓词,它会锁定范围内的所有匹配键以及范围末尾的“下一个”键(ffffffffffff
如果不存在“下一个”键,则表示无穷大)。甚至可以在此范围键锁定中使用已删除的“幽灵”记录。
如此处所述,对于唯一或非唯一索引上的相等谓词
如果键不存在,则对唯一和非唯一索引的“下一个”键进行“范围”锁定。如果“next”键不存在,则对“infinity”值进行范围锁定。
因此,对于一个空表,SELECT
仍然最终会锁定整个索引。您还需要之前在 and 之间插入一行abc
,lmn
然后您的插入才会成功。
insert into dummy values('def', 'def')