我是一个报表开发人员,想要使我的查询尽可能高效。我曾经和一个DBA一起工作,他告诉我-我相信是因为我一直在生产服务器上处理报表-可以NOLOCK
在每个查询中使用。
现在,我与一个NOLOCK
在任何情况下都被禁止使用的DBA一起工作-即使我的报告(由于在几个表上严重缺乏索引)正在停止复制和系统更新。我认为,在这种情况下,a NOLOCK
将是一件好事。
由于我的大多数SQL培训都针对不同的DBA提出了截然不同的意见,因此我想向各种各样的DBA提出这一要求。
我是一个报表开发人员,想要使我的查询尽可能高效。我曾经和一个DBA一起工作,他告诉我-我相信是因为我一直在生产服务器上处理报表-可以NOLOCK
在每个查询中使用。
现在,我与一个NOLOCK
在任何情况下都被禁止使用的DBA一起工作-即使我的报告(由于在几个表上严重缺乏索引)正在停止复制和系统更新。我认为,在这种情况下,a NOLOCK
将是一件好事。
由于我的大多数SQL培训都针对不同的DBA提出了截然不同的意见,因此我想向各种各样的DBA提出这一要求。
Answers:
如果您的报告阻止DBA正确的更新:您绝对不应使用NOLOCK
。张女士说,有有冲突清楚地表明,如果你会用脏读,你会得到不正确的报告。
我认为,总有比NOLOCK
以下更好的选择:
SET TRANSACTION ISOLATION LEVEL
,而不是查询提示。以后修复隔离级别而不是修改每个查询将更加容易。这并不总是坏的。
当然,它允许您读取未提交的值(这些值可能会回滚,因此从逻辑上讲是不存在的),以及允许出现多次读取值或根本不读取值的现象。
唯一可确保您不会遇到此类异常的隔离级别是可序列化/快照。如果在扫描到达此行之前移动了行(由于更新了键),则在可重复读值不足的情况下会丢失;如果键更新导致先前读取的行向前移动,则读未提交的值可被读取两次。
nolock
但是,由于在默认情况下,在此隔离级别下,当估计要读取的页数超过64页时,它将使用分配排序的扫描,因此很可能会出现这些问题。以及由于索引键更新导致行在页面之间移动时出现的问题类别,这些分配排序的扫描也容易受到页面拆分问题的影响(如果新分配的页面在文件中早于该点,则行可能会丢失)已扫描或读取两次(如果已扫描的页面在文件中拆分为下一页)。
至少对于简单(单表)查询,可以nolock
通过简单ORDER BY index_key
地在查询中添加an ,从而使is 的Ordered
属性阻止使用这些扫描并获得键排序的扫描。IndexScan
true
但是,如果您的报表应用程序不需要绝对精确的数字,并且可以容忍这种不一致的可能性更大,则可以接受。
但是,当然,您不应该在所有查询上都放弃它,希望它是一个神奇的“ turbo”按钮。在该隔离级别遇到异常结果的可能性更大,或者根本没有结果(“由于数据移动而无法继续使用NOLOCK进行扫描”错误),甚至在某些情况下,其性能nolock
可能会更差。
我创建的大多数报告都不会在当前数据上运行。大多数客户的运行报告是昨天的数据。如果是这样,您的答案会改变吗?
如果是这种情况,那么您还有一个可能的选择:您可以在生产数据库的副本中运行报表,
而不是在生产数据库上运行查询并弄乱锁和NOLOCK
,而无需执行任何操作。
您可以对其进行设置,以便每晚自动从备份中还原它。
显然,您的报告在客户站点上的服务器上运行,因此我不知道设置此设置是否对您而言是可行的解决方案。
(但是再说一次……无论如何,它们都应该有备份,因此您只需要一些服务器空间即可还原它们)
我是内部开发人员,因此对我来说比较容易,因为我可以完全控制服务器和数据库。
您至少可以对仅需要昨天和更早的数据的报告执行此操作。也许某些报告必须保留在生产数据库中,但是至少您将部分负载移至另一个数据库(甚至更好的是,另一个服务器)。
我在工作中也
遇到相同的情况:我们几乎将所有此类报表使用这样的生产数据库副本,但是有一些查询需要今天的数据。