值得考虑的更好选择是为数据库本身启用 READ COMMITTED SNAPSHOT。这使用 tempdb 中的版本控制来捕获事务开始时表的状态。
关于 NOLOCK、READPAST 等各个方面的内容非常好,位于http://www.brentozar.com/archive/2013/01/implementing-snapshot-or-read-comfilled-snapshot-isolation-in-sql-server-a-guide/ http://www.brentozar.com/archive/2013/01/implementing-snapshot-or-read-committed-snapshot-isolation-in-sql-server-a-guide/
WITH (NOLOCK)
如果您在从表中进行选择时有人正在更新表,则可能会提供不正确的结果。如果在读取表格时由于插入而发生分页,并且新页恰好超出了您已读取的点,WITH (NOLOCK)
将从旧页面返回行,然后从新页面返回重复行。这只是一个简单的例子来说明原因(NOLOCK)
is bad.
WITH (READPAST)
当您从表中读取数据时,将跳过任何正在更新或插入的记录。对于繁忙的数据库来说,这两种选择都不好。
鉴于最近对您的问题的编辑,您指出您无法更改数据库设置READ COMMITTED SNAPSHOT
,也许您应该考虑使用存储过程来收集报告数据,并使用以下命令在存储过程的开头设置事务隔离级别SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
。为此,您需要更改数据库选项“允许快照隔离”。
来自 SQL Server 在线书籍:
SNAPSHOT
指定事务中任何语句读取的数据将是事务开始时存在的数据的事务一致版本。事务只能识别在事务开始之前提交的数据修改。当前事务开始后其他事务所做的数据修改对于当前事务中执行的语句不可见。效果就好像事务中的语句获取了事务开始时存在的已提交数据的快照。
除恢复数据库外,SNAPSHOT 事务在读取数据时不会请求锁。 SNAPSHOT 事务读取数据不会阻止其他事务写入数据。写入数据的事务不会阻止 SNAPSHOT 事务读取数据。
在数据库恢复的回滚阶段,如果尝试读取被回滚的另一个事务锁定的数据,SNAPSHOT 事务将请求锁定。 SNAPSHOT 事务将被阻止,直到该事务被回滚。锁被授予后立即释放。
必须先将 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON,然后才能启动使用 SNAPSHOT 隔离级别的事务。如果使用 SNAPSHOT 隔离级别的事务访问多个数据库中的数据,则必须在每个数据库中将 ALLOW_SNAPSHOT_ISOLATION 设置为 ON。
事务不能设置为以其他隔离级别开始的 SNAPSHOT 隔离级别;这样做将导致事务中止。如果事务在 SNAPSHOT 隔离级别下启动,您可以将其更改为另一个隔离级别,然后再返回到 SNAPSHOT。事务在第一次访问数据时启动。
在 SNAPSHOT 隔离级别下运行的事务可以查看该事务所做的更改。例如,如果事务对表执行 UPDATE,然后对同一表发出 SELECT 语句,则修改后的数据将包含在结果集中。