SQL Server 如何处理并行 UPDATE 事务,该事务可能会生成与第一个事务的 WHERE 子句匹配的行?

var*_*ble 3 sql-server sql-server-2019

假设我有以下情况:

事务 1 使用 WHERE 子句执行 UPDATE,但尚未提交

UPDATE TBL SET VAL1=10 WHERE VAL2=100
Run Code Online (Sandbox Code Playgroud)

事务 2 尝试 SELECT 不属于上述 WHERE 子句的行。假设存在索引,并且数据库引擎决定对表、页采用 IX 锁,对属于 WHERE 子句的行采用 X 锁,则该查询将起作用。

现在,假设事务 2 是对不属于 SELECT 查询的 WHERE 子句的行的 UPDATE 查询。

UPDATE TBL SET VAL2=100 WHERE VAL1=500
Run Code Online (Sandbox Code Playgroud)

当上面的查询运行时,假设如上所述持有相同的锁,则会导致更多行满足 VAL2=100 条件(这也是第一次 UPDATE 中的 WHERE 子句)。SQL如何处理这种情况呢?

例如,当sql server看到事务2的更新时,它是否意识到这一点并将事务1的锁升级为表锁,并且不允许事务2的更新发生?

Pau*_*ite 9

如果您具体询问当 T1 已完成但未提交时可能会发生什么,一般答案是 T1 不受 T2* 所做的任何更改的影响。T2 可能会或可能不会阻塞,具体取决于隔离级别以及它用来定位应更新的行的访问方法(索引路径)。

* 一个例外是,如果 TBL 是内存优化表,并且 T1 在需要在提交时进行验证的隔离级别下运行。在该特定场景中,可能会发生序列化或可重复读取失败,并且 T1 将回滚并出现错误。请参阅文档

如果您问 T1 和 T2同时执行时会发生什么:

在可序列化隔离下,两个事务对用户数据持久状态的影响将事务按某种顺序串行运行(一个接一个)相同。

如果效果就像​​ T2 首先运行完成一样,则事务 T1 将更新受 T2 影响的行。否则,效果就好像 T1 先完成,然后 T2 开始。

任何一种结果都是可行的。您在实践中会看到什么取决于时间。请注意,效果是“好像”的。两笔交易在时间上仍可能重叠。


在其他隔离级别,可能会出现更广泛的结果。事务 T1 可能不会遇到受 T2 影响的行、部分行或全部行。

在快照隔离下,如果事务 T1 遇到自事务启动以来 T2(或任何其他人)修改的行,则事务 T1 可能会失败并出现错误。