[英]Unexpected behaviour of the Serializable isolation level
测试设置
我有一个 SQL Server 2014 和一个简单的表MyTable
,其中包含列Code (int)
和Data (nvarchar(50))
,没有为此表创建索引。
我以下列方式在表中有 4 条记录:
1, First
2, Second
3, Third
4, Fourth
然后我在事务中运行以下查询:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
DELETE FROM dbo.MyTable
WHERE dbo.MyTable.Code = 2
我有一个受影响的行,我没有发出 Commit 或 Rollback。
接下来我开始另一个事务:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT TOP 10 Code, Data
FROM dbo.MyTable
WHERE Code = 3
在这一步,使用 SELECT 查询的事务挂起,等待使用 DELETE 查询的事务完成。
我的问题
我不明白为什么带有 SELECT 查询的事务正在等待带有 DELETE 查询的事务。 据我了解,删除的行(代码 2)与所选行(代码 3)无关,据我了解,隔离级别 SERIALIZABLE SQL 服务器在这种情况下不应该锁定整个表。 也许发生这种情况是因为 SERIALIZABLE 的最小锁定量是一个页面? 然后,如果表有更多行,例如 1000000(其他页面中的某些行不会被锁定),那么它可能会产生从其他页面中选择行的不一致行为。 请帮助弄清楚为什么在我的情况下会发生锁定。
在锁定 READ COMMITTED、REPEATABLE READ 或 SERIALIZABLE 下,SELECT 查询必须为查询计划实际读取的每一行放置共享 (S) 锁。 锁可以放置在行级、页级或表级。 此外,SERIALIZABLE 将在范围上放置锁,以便在持有锁时没有其他 session 可以插入匹配的行。
而且因为您“没有为此表创建索引”,所以这个查询:
SELECT TOP 10 Code, Data
FROM dbo.MyTable
WHERE Code = 3
必须使用表扫描执行,并且必须读取所有行(即使是 Code=2 的行)以确定它们是否符合 SELECT 的条件。
这就是为什么您应该几乎总是使用Row-Versioning 的原因之一,或者通过将数据库设置为 READ COMMITTED SNAPSHOT,或者通过编码只读事务以使用 SNAPSHOT 隔离。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.