如何在 SQL UPDATE 语句 WHERE 子句中读取脏值
Posted
技术标签:
【中文标题】如何在 SQL UPDATE 语句 WHERE 子句中读取脏值【英文标题】:How can I read dirty values in SQL UPDATE statement WHERE clause 【发布时间】:2021-10-18 18:16:11 【问题描述】:假设我在两个单独的 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 完成
【问题讨论】:
在我的应用程序中,我将有 2 个(或更多)进程运行它,我希望进程 2 应该能够拾取进程 1 尚未拾取的行;我不希望进程 2 需要等到进程 1 完成 状态列的基数是多少,有多少行可能处于任一状态? 可能每个状态都以50开头;随着时间的推移,它会变得更多 我不相信你在这里想要read uncommitted
,你只需要跳过已经被事务锁定的行,你可以使用with(readpast)
提示来完成
解决方案可能是变得更严格,而不是更少,并确保每个操作尽可能短。这可能意味着将现有的长时间运行的作业分解为更小的幂等步骤。
【参考方案1】:
你所要求的根本不可能。
即使在READ UNCOMMITTED
(又名NOLOCK
)的最低隔离级别,也必须使用X-Lock
(专有)才能进行修改。换句话说,写入总是被锁定,即使读取这些行的读取没有被锁定。
因此,即使会话 2 也在 READ UNCOMMITTED
下运行,如果它想要进行修改,它也必须采用 X-Lock
,这与第一个 X-Lock 不兼容。
这里的解决方案是在一个会话中执行此操作,或者立即提交。 在任何情况下,都不要持有任何时间长度的锁,因为它会导致大量阻塞链甚至死锁.
如果您只想忽略所有已插入的行,可以使用WITH (READPAST)
提示。
READ UNCOMMITTED
作为隔离级别或作为提示存在很大问题。
它可能导致从死锁到完全不正确的结果。例如,您可以读取一行两次,或者根本不读取,而根据模式的逻辑定义,应该正好只有一行。您可以阅读整页两次或根本不阅读。
由于U-Lock
s 未包含在UPDATE
和DELETE
语句中,您可能会遇到死锁。
而且您仍然会使用架构锁,因此您仍然可能会陷入同步统计信息更新或索引重建之后。
【讨论】:
以上是关于如何在 SQL UPDATE 语句 WHERE 子句中读取脏值的主要内容,如果未能解决你的问题,请参考以下文章
oracle SQL查询中,如何在where中用条件语句,判断不同情况,追加不同的And条件?
Pandas 获得与 SQL 语句相同结果的 Pythonic 方式是啥:“UPDATE-LEFT JOIN - SET - WHERE”?