Reputation: 552
Given the following running transaction:
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
If within the waitfor
delay I launch the following request:
select value from T(updlock) where id = 'id1'
This request blocks until transaction t
completes, and then returns the result new
as expected.
But if instead I launch the following request:
select value from T where id in (select id from T(updlock) where id = 'id1')
This request is also blocked by t
, but then the result is old
.
Why is that?
Upvotes: 2
Views: 244
Reputation: 452988
This is entirely possible. I'm not sure why you think it wouldn't be. 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')
has an implied predicate though that is not relevant to the behaviour you see. The execution plan is the same as below (with the seek on 'id1' copied to the T1 branch and an uncorrelated sub query)
SELECT T1.value
FROM T T1
WHERE T1.id = 'id1'
AND EXISTS (SELECT *
FROM T(updlock) T2
WHERE T2.id = 'id1')
Your SELECT
query in the first window takes an UPDLOCK
on the row and holds it for 10 seconds - however this is compatible with the S
lock required by the seek on T1
in window 2 so that seek emits a row with the value
column to the nested loops operator. Then the nested loops requests a row from its second input (the seek on T2
). This has the UPDLOCK
hint so is blocked.
Eventually the first window converts its UPDLOCK
to an X
lock, releases its lock and the seek on T2
is unblocked. It then emits a row (with no columns so completely unaffected by the fact that value
has changed). This means that the semi join condition (EXISTS
predicate) is met and the original row is passed along to the root iterator and output.
Upvotes: 1