NOLOCK
。 现在,我与一个在任何情况下都禁止
NOLOCK
的DBA一起工作-即使我的报告(由于几个表上的索引严重不足)正在停止复制和系统更新。我认为,在这种情况下,NOLOCK
将是一件好事。 由于我的大多数SQL培训都来自于对DBA的看法迥异,所以我想向各种各样的DBA提出这个问题。
#1 楼
如果您的报告阻止DBA是正确的更新:绝对不要使用NOLOCK
。存在冲突的事实清楚地表明,如果您使用脏读,将会得到不正确的报告。 我认为,总是有比
NOLOCK
更好的替代方法:将数据库标记为只读! 表扫描会导致锁冲突?正确索引表,好处是多方面的。
不能修改/不知道如何正确索引?使用快照隔离。
不能将应用更改为使用快照吗?打开已读的已提交快照!
您已经测量了行版本控制的影响,并有证据证明它会影响性能吗?您无法索引数据?您可以接受不正确的报告吗?然后至少要帮自己一个忙,并使用
SET TRANSACTION ISOLATION LEVEL
而不是查询提示。以后修复隔离级别而不是修改每个查询将变得更加容易。评论
注意:打开已读提交的快照可能会破坏一些代码。
–A-K
2012年1月14日,下午3:36
#2 楼
这并不总是坏的。当然,它允许您读取未提交的值(这些值可能会回滚,因此从逻辑上讲是不存在的),并允许出现多次读取或根本不读取值的现象。 br />唯一可以确保您不会遇到此类异常的隔离级别是可序列化/快照。如果在扫描到达此行之前移动了行(由于更新了键),则在可重复读值不足的情况下会丢失;如果键更新导致先前读取的行向前移动,则读未提交的值可能会被读取两次。
这些问题很可能在
nolock
下出现,因为默认情况下,在此隔离级别下,当估计要读取的页数超过64页时,它将使用分配有序扫描。以及由于索引键更新导致行在页面之间移动时出现的问题类别,这些分配排序的扫描也容易受到页面拆分问题的影响(如果新分配的页面在文件中早于该点,则行可能会丢失。已扫描或读取两次(如果已扫描的页面被拆分到文件中的下一页)。只需在查询中添加一个nolock
即可在ORDER BY index_key
处进行键有序扫描,从而使Ordered
的IndexScan
属性为true
。这种不一致的可能性是可以接受的。在此隔离级别遇到异常结果的可能性更大,或者根本没有结果(“由于数据移动而无法继续使用NOLOCK进行扫描”错误),甚至nolock
的性能可能会更差。 />评论
马丁,我会提出一些略有不同的词:“在读取的情况下,提交的值既可能被遗漏,也可能被多次读取”。在某些特殊情况下,我们可以使行被检索两次以上。
–A-K
2012年1月14日下午3:06
#3 楼
您的客户是否可以容忍报告中的不一致结果?如果答案是否定的,则不应使用NOLOCK-在并发下可能会得到错误的结果。我在这里,这里和这里写了一些例子。这些示例在READ COMMITTED和REPEATABLE READ下显示了不一致的输出,但是您可以对其进行调整,并使用NOLOCK也得到错误的结果。评论
我创建的大多数报告都不会在当前数据上运行。大多数客户的运行报告是昨天的数据。如果是这种情况,您的答案会改变吗?
–DataGirl
2012年1月15日下午4:26
#4 楼
我创建的大多数报告都不会在当前数据上运行。大多数客户的运行报告是昨天的数据。如果是这样,您的答案会改变吗?
如果是这种情况,那么您还有另一个可能的选择:
而不是在生产数据库上运行查询并弄乱了周围带有锁和
NOLOCK
,您可以从生产数据库的副本中运行报告。 您可以进行设置,以便每晚自动从备份中恢复。
您的报告显然在客户站点的服务器上运行,因此我不知道是否进行设置为您提供一个可行的解决方案。(但是再次...无论如何,它们都应该有备份,因此您只需要一些服务器空间即可还原它们)
我是内部开发人员,因此对我来说更容易,因为我可以完全控制服务器和数据库。也许某些报告必须保留在生产数据库中,但是至少您将一些负载移到了另一个数据库(甚至更好的是,另一个服务器)上。 :
几乎所有报告内容我们都使用这样的生产数据库副本,但是有一些查询需要今天的数据。
评论
讨论的另一面:dba.stackexchange.com/q/2684/2660