Q1:是的,至少在理论上这是完全可能的。read committed
只是保证您不会读取脏数据,它不承诺一致性。在读取提交级别,共享锁在数据被读取后立即释放(不是在事务结束时,甚至不是在语句结束时)
Q2:是的,如果打开,这个问题的答案会改变read_committed_snapshot
。然后,您将得到保证语句级别的一致性。我发现很难找到明确说明这一点但引用“Microsoft SQL Server 2008 Internals”的 p.648 的在线资源
RCSI 中的语句会看到在语句开始之前提交的所有内容。事务中的每个新语句都会获取最近提交的更改。
另请参阅此 MSDN 博客文章
设置脚本
CREATE TABLE person
(
id int primary key,
name varchar(50)
)
INSERT INTO person
values(1, 'foo');
连接 1
while 1=1
update person SET name = CASE WHEN name='foo' then 'bar' ELSE 'foo' END
连接 2
DECLARE @Results TABLE (
id int primary key,
name1 varchar(50),
name2 varchar(50))
while( NOT EXISTS(SELECT *
FROM @Results) )
BEGIN
INSERT INTO @Results
Select p1.id,
p1.name,
p2.name
from person p1
INNER HASH join person p2
on p1.id = p2.id
WHERE p1.name <> p2.name
END
SELECT *
FROM @Results
结果
id name1 name2
----------- ----- -----
1 bar foo
merge
查看 Profiler 中的其他连接类型,似乎在此特定查询的连接或计划下都不会出现此问题nested loops
(在获取所有锁之前不会释放锁),但重点仍然是read committed
保证您不会读取脏数据不承诺一致性。实际上,对于您发布的确切查询,您可能不会遇到此问题,因为默认情况下 SQL Server 不会选择此连接类型。但是,您只需要依靠实现细节来产生您想要的行为。

注意:如果您想知道为什么某些行级S
锁似乎丢失了,这是此处解释的优化。