繁体   English   中英

可序列化隔离级别的意外行为

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM