如何读取SQL UPDATE语句WHERE子句中的脏值?



假设我在两个独立的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作为隔离级别或提示存在巨大问题。

它可能导致从死锁到完全错误的结果。例如,您可以读取一行两次,或者根本不读取,而根据模式的逻辑定义,应该只有一行。你可以把整页读两遍,或者根本不读。

UPDATEDELETE语句中,U-Locks没有被占用,可能会导致死锁。

并且您仍然使用模式锁,因此您仍然可以在同步统计更新或索引重建之后卡住。

相关内容

  • 没有找到相关文章

最新更新