鉴于以下正在运行的事务:
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
如果在waitfor
延迟时间内,我发起以下请求:
select value from T(updlock) where id = 'id1'
此请求将阻塞,直到事务t
完成,然后按预期返回结果new
。
但如果我改为启动以下请求:
select value from T where id in (select id from T(updlock) where id = 'id1')
t
也阻止了此请求,但结果为old
。
为什么?
答案 0 :(得分:1)
这完全有可能。我不确定你为什么认为它不会。 S
locks are not blocked by U
locks
SELECT T1.value
FROM T T1
WHERE T1.id IN (SELECT T2.id
FROM T(updlock) T2
WHERE T2.id = 'id1')
有一个implied predicate,但这与您看到的行为无关。执行计划与下面相同(将'id1'的搜索复制到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秒钟 - 但这与S
搜索所需的T1
锁兼容1}}在窗口2中,以便查找使用value
列向嵌套循环运算符发出一行。然后嵌套循环从其第二个输入(T2
上的搜索)请求一行。这有UPDLOCK
提示,因此被阻止。
最终,第一个窗口将其UPDLOCK
转换为X
锁定,释放其锁定,并且T2
上的搜索被解除阻止。然后它会发出一行(没有列,所以完全不受value
已更改的事实的影响)。这意味着满足半连接条件(EXISTS
谓词),并将原始行传递给根迭代器并输出。