假设我在两个独立的SSMS查询窗口中有以下查询:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION
UPDATE dbo.Jobs
SET [status] = 'Running'
OUTPUT Inserted.*
WHERE [status] = 'Waiting'
--I'm NOT committing yet
--Commit Transaction
我运行查询窗口1(但不提交),然后我运行查询窗口2。
我希望查询窗口2立即只更新在我开始查询1后插入的行(所有新记录都以'等待'的状态进入)。然而,SQL Server正在等待第一个查询完成,因为在update语句中它没有读取脏值(即使它被设置为READ UNCOMMITTED);
有办法克服这个吗?
在我的应用程序中,我将有2个(或更多)进程运行它,我希望进程2应该能够拾取进程1没有拾取的行;我不希望进程2需要等待直到进程1完成
你所要求的根本是不可能的。
即使在READ UNCOMMITTED
(即NOLOCK
)的最低隔离级别,也必须取X-Lock
(独占)才能进行修改。换句话说,写操作总是被锁定的,即使读取这些行没有被锁定。
因此,即使会话2也在READ UNCOMMITTED
下运行,如果它想要进行修改,它也必须使用X-Lock
,这与第一个X-Lock不兼容。
这里的解决方案是在一个会话中执行此操作,或者立即提交。在任何情况下,不要长时间持有锁,因为它可能导致大量的阻塞链,甚至死锁。
如果你想忽略所有已经插入的行,你可以使用WITH (READPAST)
提示。
READ UNCOMMITTED
作为隔离级别或提示存在巨大问题。
它可能导致从死锁到完全错误的结果。例如,您可以读取一行两次,或者根本不读取,而根据模式的逻辑定义,应该只有一行。你可以把整页读两遍,或者根本不读。
在UPDATE
和DELETE
语句中,U-Lock
s没有被占用,可能会导致死锁。
并且您仍然使用模式锁,因此您仍然可以在同步统计更新或索引重建之后卡住。