丢失行和重复行的症状是由于分配顺序扫描还是由于无锁和页拆分所致?

var*_*ble 0 index sql-server isolation-level nolock

NOLOCK 导致分配顺序扫描而不是索引顺序扫描。

NOLOCK 不会阻止写入,因为它不在表上获取共享锁。

在NOLOCK扫描期间,由于没有共享锁,并且在扫描当前到达的点之前发生了写入(插入/更新),那么这种情况将导致记录丢失。

类似地,在写入(插入/更新)期间,当读取一行后发生页拆分,并且该行现在是下一页的一部分(由于页拆分),那么这种情况将导致重复记录。

我一直在阅读文章,这些文章似乎表明丢失/重复行问题是由于分配顺序扫描造成的。

  1. 如上面的示例所示,丢失/重复记录问题是由于没有锁定和页面拆分造成的。正确的?是否也是分配顺序扫描导致的?

  2. 如果分配有序扫描确实会导致丢失行/重复项,那么我想问 - 假设引擎使用了索引顺序扫描(我知道引擎不会这样做,但只是为了这个问题而假设)而不是分配顺序扫描,那么它将如何解决丢失/重复行问题?

Pau*_*ite 11

NOLOCK 导致分配顺序扫描而不是索引顺序扫描。

这是不正确的。使用未提交读意味着存储引擎可以在分配顺序和索引顺序扫描之间进行选择。它可以在运行时选择任一策略,而无需重新编译执行计划。

NOLOCK 不会阻止写入,因为它不在表上获取共享锁。

以读未提交的方式读取数据意味着不会在行、页或表粒度上获取共享锁。由于没有获取这些锁,因此它们不会阻塞并发事务更改数据所需的排他锁。

在NOLOCK扫描期间,由于没有共享锁,并且在扫描当前到达的点之前发生了写入(插入/更新),那么这种情况将导致记录丢失。

这并不特定于未提交的读取。使用锁定读已提交或可重复读来读取数据也可能会丢失已提交的数据。

锁定已提交读通常会在读取下一行之前释放一行上的共享锁:

读已提交

可重复读将共享锁维持到事务结束,但只有到目前为止实际遇到的数据才会被锁定。如果索引键值更改,当前扫描位置前面的行可能会移动到扫描点后面:

可重复读取

克雷格·弗里德曼 (Craig Freedman) 帖子中的先前图片内联链接

上述问题特定于索引顺序扫描


类似地,在写入(插入/更新)期间,当读取一行后发生页拆分,并且该行现在是下一页的一部分(由于页拆分),那么这种情况将导致重复记录。

索引顺序扫描不关心页面分割。在分割之前和之后,页面都按逻辑键顺序链接。索引顺序扫描将遇到拆分页上的行以及拆分产生的新页。如果您按关键顺序关注页面,则无法避免这种情况。

  1. 如上面的示例所示,丢失/重复记录问题是由于没有锁定和页面拆分造成的。正确的?是否也是分配顺序扫描导致的?

不,这些是由于在进行索引顺序扫描时按索引顺序移动行而多次丢失或遇到行的示例。

由于页面拆分而丢失或多次遇到行的问题只有在使用分配顺序扫描时才会发生。按分配顺序扫描时,页面拆分会将某些行移动到新页面。分配顺序扫描可能会或可能不会遇到该新页面。如果已经遇到分割的页面,我们会再次看到一些行。如果尚未遇到分割页,如果新页落后于分配顺序扫描位置,我们可能会丢失一些行。

仅当引擎具有可接受的保证数据在扫描期间不会更改时,才可以在不使用未提交读的情况下进行分配顺序扫描。因此,由于对更改的数据进行按分配顺序的扫描而导致丢失已提交的行或多次遇到这些行,因此特定于使用读未提交隔离。

  1. 如果分配有序扫描确实会导致丢失行/重复项,那么我想问 - 假设引擎使用了索引顺序扫描(我知道引擎不会这样做,但只是为了这个问题而假设)而不是分配顺序扫描,那么它将如何解决丢失/重复行问题?

使用索引顺序扫描可以避免由于页面分割而导致的丢失/重复行,如上所述。由于索引键更改,仍然可能会出现丢失或重复的行,也如上所述。

再次注意:使用未提交的读并不能保证您获得分配顺序扫描。

进一步阅读: