1

假设我在两个单独的 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 正在等待第一个查询完成,因为在更新语句中它没有读取脏值(即使它设置为 READ UNCOMMITTED);

有没有办法克服这个问题?

在我的应用程序中,我将有 2 个(或更多)进程运行它,我希望进程 2 应该能够拾取进程 1 没有拾取的行;我不希望流程 2 需要等到流程 1 完成

4

1 回答 1

1

你所要求的根本是不可能的。

即使在READ UNCOMMITTED(aka NOLOCK)的最低隔离级别,也必须X-Lock采用(exclusive)才能进行修改。换句话说,写入总是被锁定,即使读取这些行的读取没有被锁定。

因此,即使会话 2READ UNCOMMITTED也在运行,如果它想要进行修改,它也必须采用一个X-Lock,这与第一个 X-Lock 不兼容。

这里的解决方案是在一个会话中执行此操作,或者立即提交。无论如何,不​​要长时间持有锁,因为它会导致大量阻塞链甚至死锁。

如果您只想忽略所有已插入的行,则可以使用WITH (READPAST)提示。


READ UNCOMMITTED作为隔离级别或提示有很大的问题。

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

由于U-Locks 未包含在UPDATEDELETE语句中,您可能会出现死锁。

而且您仍然会使用模式锁,因此您仍然可能会被同步统计信息更新或索引重建所困。

于 2021-10-18T20:30:12.620 回答