执行顺序删除和未提交读

kan*_*anu 3 sql-server-2008 sql-server isolation-level nolock

我们正在使用动态 SQL 运行以下查询,当我们运行并发实例时,它会在少数情况下出错。错误是:

由于数据移动,无法使用 NOLOCK 继续扫描...

这个问题说当一个进程读取另一个进程正在删除的数据时会抛出这个错误。我们的过程是删除和读取相同的行,但是按照以下查询一个接一个地读取(在SELECT之后DELETE):

DELETE FROM Table1
WHERE colum1 = somevalue1
AND column2 = somevalue2

SELECT COUNT(*) 
FROM Table1 WITH (NOLOCK)
WHERE colum1 = somevalue1
AND column2 = somevalue2
Run Code Online (Sandbox Code Playgroud)

我试图了解上述查询的执行。由于SELECT未提交,它是否在提交之前开始执行DELETE?这是否意味着删除NOLOCK提示会停止错误?

Pau*_*ite 6

由于SELECT未提交,它是否在提交之前开始执行DELETE

不,T-SQL 语句总是在 SQL Server 中按顺序执行。关键是其他并发执行的事务SELECT可能会读取未提交的更改

这是否意味着删除NOLOCK应该停止错误?

是的,但只是因为错误 601仅在事务隔离级别READ UNCOMMITTED. 移动到不同的隔离级别可防止发生该特定错误。

附加信息

错误 601 的发生有多种原因,但都有一个共同的主题:SQL Server 引擎正在跟踪某个指针链或其他,当它遇到它期望存在的结构已被另一个移动或删除的情况时并发执行过程。

可能发生错误 601 的情况在 SQL Server 版本中逐渐减少,SQL Server 2012 最不可能返回此错误,尽管仍有可能。

我自己的观点是,所有错误 601 事件都是错误 - 对于“错误”的合适值。这种行为当然是不可取的,并且远远超出了 SQL 标准对READ UNCOMMITTED隔离级别下可能遇到的现象的描述。

虽然这是千真万确的SQL标准没有定义不同的隔离级别的详细行为非常好,它做什么要说到共同的信念导致了唯一的后果READ UNCOMMITTED是,交易可能会看到已被其他变化的数据在其他事务提交之前的事务。因此,使用READ UNCOMMITTED隔离级别通常是合理的,因为几乎所有事务都提交得非常快(并且很少回滚),因此读取“脏”数据只是时间差异。

不幸的是,READ UNCOMMITTEDSQL Server 中的 实现不止简单的脏读。READ UNCOMMITTEDSQL Server 中的事务可能返回重复数据、大数据类型的部分读取、完全跳过数据记录,或者只是因 601 错误而失败。

可能READ COMMITTED 甚至 下体验这些行为中的一些REPEATABLE READ。这导致一些人认为唯一可以接受的隔离级别是指那些提供至少语句级的一致性,即row-versioning READ COMMITTEDSNAPSHOT隔离,或SERIALIZABLE

其中,row-versioning READ COMMITTED通常是最容易过渡到的。有关行版本控制隔离级别的详细信息,请参阅此联机丛书主题及其子树。