Sql server 使用子查询时结果不一致

Sql server 使用子查询时结果不一致,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,给定以下正在运行的事务: begin tran t select 1 from T(updlock) where id = 'id1' waitfor delay '00:00:10' update T set value = 'new' where id = 'id1' commit tran t 如果在等待延迟时间内,我启动以下请求: select value from T(updlock) where id = 'id1' select value from T where id in

给定以下正在运行的事务:

begin tran t
select 1 from T(updlock) where id = 'id1'
waitfor delay '00:00:10'
update T set value = 'new' where id = 'id1'
commit tran t
如果在等待延迟时间内,我启动以下请求:

select value from T(updlock) where id = 'id1'
select value from T where id in (select id from T(updlock) where id = 'id1')
此请求阻塞直到事务t完成,然后按预期返回新结果

但如果我启动以下请求:

select value from T(updlock) where id = 'id1'
select value from T where id in (select id from T(updlock) where id = 'id1')
此请求也被t阻止,但结果是旧的

为什么呢

附件:执行计划
这是完全可能的。我不知道你为什么不这么认为

具有与您看到的行为无关的想法。执行计划如下所示,将“id1”上的seek复制到T1分支和一个不相关的子查询

SELECT T1.value
FROM   T T1
WHERE  T1.id = 'id1'
       AND EXISTS (SELECT *
                   FROM   T(updlock) T2
                   WHERE  T2.id = 'id1') 
第一个窗口中的SELECT查询在该行上获取一个UPDLOCK并保持10秒,但是这与窗口2中T1上的seek所需的S锁兼容,因此seek向嵌套循环操作符发出一个带有值列的行。然后嵌套循环从第二个输入请求一行,即T2上的seek。这有UPDLOCK提示,因此被阻止


最后,第一个窗口将其UPDLOCK转换为X锁,释放其锁,T2上的seek被解锁。然后,它将发出一个没有列的行,因此完全不受值已更改的事实的影响。这意味着满足半联接条件EXISTS谓词,原始行被传递到根迭代器并输出。

您是在事务完成后还是在此之前运行selects。由于这部分在等待延迟内比较混乱,并且您还声明了事务t完成。您是否也可以共享两个事务的执行计划选择SOK,编辑以澄清。这不可能。您可以添加执行计划并粘贴它吗here@TheGameiswar在SQL Server 2012上复制。我理解。但是,如果导致绕过锁逻辑,为什么优化器允许将“id1”上的seek拉到外部查询?从我天真/非专家的角度来看,在第一个窗口中,外部查询输入取决于内部查询输出,因此这里有一些排序。这就是为什么我希望在外部查询输入输入时释放内部查询的updlock锁,因此外部查询将在事务更新后运行,并返回更新的值。@lledr-正如我在回答中所述,这不是您看到的行为的原因。即使谓词没有被推入T1,并且它扫描了所有行并使用了相关子查询,同样的行为仍然可能发生,因为T1上的扫描只接受S锁,而更新锁直到T2上的搜索才被接受。不过,通常情况下,优化器可以自由地使用锁定提示优化分支。e、 g.select*from从Tupdlock中选择值,其中id='id1'而不是其中1=0根本不锁定行。