什么时候适合使用NOLOCK?

时间:2009-05-03 09:14:07

标签: sql sql-server-2005 deadlock nolock

我有一些长时间运行的查询时不时出现超时问题和死锁。

我想知道什么时候最适合使用NOLOCK以及在哪里?

我是否在更新时使用它?插入?还是读?

6 个答案:

答案 0 :(得分:6)

请注意,您可以基于每个表指定nolock。

我通常在复杂的SELECT查询中使用nolock,但仅用于几乎从不更改的小查找表,以及仅显示数据。您知道列出当前半年价格的表格,或者查找ID到字符串等的表格。只有在主要更新之后才会发生变化,之后通常会重新启动服务器。

这显着改善了性能,减少了在最繁忙时间出现死锁的可能性,更重要的是,在最糟糕的情况下,触及很多表的查询真的很明显(这是合乎逻辑的,它们必须获得更少的锁,而且这些边桌经常在几乎所有地方使用,通常从7-8个减少到4个需要锁定的桌子。

但是要非常小心地添加它,不要急于它,并且不要经常这样做。如果使用得当,它不会受到伤害,但如果使用不当会伤害到它。

不要将它用于高度关键的东西,计算等的东西,因为它会变得不一致,迟早会导致写入的任何东西。

另一个这样的优化是ROWLOCK,它只锁定在行级别上。这在更新(或删除)行彼此无关的表时非常有用,例如只放入日志记录的表(以及插入它们的顺序无关紧要)。如果你有一个方案,在事务结束的某个地方将日志记录写入某个表,这也会大大加快。

如果您的数据库写入百分比相对较低,则可能不值得。我的读写比率低于2:1。

我在处理这个时保存的一些网址:

http://www.developerfusion.com/article/1688/sql-server-locks/4/

答案 1 :(得分:5)

SQL Server中有四个transaction isolation levels

  1. READ UNCOMMITTED
  2. READ COMMITTED
  3. REPEATABLE READ
  4. SERIALIZABLE
  5. 对于它所应用的表,NOLOCK相当于“read uncommitted”。这意味着您可以查看将来可能会回滚的事务中的行,以及许多其他奇怪的结果。

    尽管如此,诺洛克在实践中表现得非常好。特别是对于只读查询,显示略有错误的数据不是世界末日,如业务报告。我会在更新或插入附近,或者通常在决策代码附近的任何地方避免它,特别是如果它涉及发票。

    作为nolock的替代方案,请考虑“读取已提交的快照”,这适用于具有大量读取和较少写入活动的数据库。你可以用以下方式打开它:

    ALTER DATABASE YourDb SET READ_COMMITTED_SNAPSHOT ON;
    

    适用于SQL Server 2005及更高版本。这就是Oracle默认工作的方式,也就是stackoverflow本身使用的方式。关于它,甚至还有一个coding horror博客文章。

    P.S。长时间运行的查询和死锁也可能表明SQL Server正在使用错误的假设。检查您的统计数据或索引是否已过期:

    SELECT 
        object_name = Object_Name(ind.object_id),
        IndexName = ind.name,
        StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
    FROM SYS.INDEXES ind
    order by STATS_DATE(ind.object_id, ind.index_id) desc
    

    统计数据应在每周维护计划中更新。

答案 2 :(得分:3)

使用nolock作为最后的手段。可以通过调整查询和/或调整索引来解决大多数死锁问题。我想我已经看到过去5年中的一个僵局无法通过调整其中一个来解决。

另请注意,NOLOCK仅适用于select语句。数据修改将始终锁定,无法更改该行为。因此,如果你有一个作家/作家死锁(很常见),没有锁根本就没用。

另请注意,除了返回脏数据之外,nolock还可能导致重复的行(从基础表中读取两次的行)和缺少的行(基础表中根本没有读取的行)。

Nolock本质上意味着SQL Server'我不介意我的结果是否有点不准确'

快照隔离是一种选择。请确保首先仔细测试,因为TempDB上的负载增加可能非常严重,具体取决于您的事务的频率和时间。另请注意,虽然您不会在快照隔离中看到死锁,但您可能会遇到更新冲突。再次,测试并确保您的应用程序正常运行并可以处理他们获得的任何错误。

答案 3 :(得分:2)

在可以接受脏读和幻像记录的情况下使用它,即您可能会定期运行非关键报告,其中信息的准确性不是主要驱动因素,但可以查看记录量或其他度量标准,例如

答案 4 :(得分:2)

当可以读取脏数据时,应该使用nolock。可能对数据库进行大量更改的大型事务可能仍在进行中,使用nolock只会返回到目前为止已设置的数据。该事务是否应该回滚您正在查看的数据可能是错误的。因此,只有当你回来的东西无关紧要时,你才应该使用它。

死锁是一个常见问题,但10次中有9次完全是由开发人员问题引起的。我会集中精力找到死锁的原因,而不是使用nolock。它很可能只是一个事务以不同的顺序处理所有其他事务。只修复那个可能会使你的所有问题都消失。

答案 5 :(得分:1)

对于没有读锁定的事务一致性视图,建议在SQL Server中启用快照隔离。

这与NOLOCK略有不同,因为当您读取信息时,结果始终反映已提交数据的版本,而不是查看未提交数据的可能性。这提供了与NOLOCK相同的锁定并发性(没有“读取”锁定),结果更清晰。

即使事务一致性,也应该始终牢记,然后您在显示或显示时使用的数据可能是错误的或过时的。我见过太多人认为如果他们足够快地使用数据,或者如果他们在查询/事务中使用它就可以了。这是荒谬的 - 我认为可重复的一致性水平从来就不应该首先实施,因为它只是鼓励不良行为。它们在Oracle中不存在。

就我个人而言,我喜欢禁用某些非关键数据视图和报告的锁定,因为它减少了对系统的负担,并且提供稍微不准确的结果的小问题不是问题。

利用可重复的读取一致性级别和犯下诸如为用户输入保持开放交易的罪行可能在初始开发方面对开发人员来说更容易,但几乎总是会导致主要的道路“障碍”到合理的希望扩展您的应用程序。

我认为最好的方法是始终“仔细检查”条件,为了对任何数据应用更新,这些条件仍然必须为真。

为:

UPDATE myaccount SET balance = 2000

更好:

UPDATE myaccount SET balance = balance + 2000

更好的是:

UPDATE myaccount SET balance = 2000 WHERE balance = 0 AND accountstatus = 1

最后,应用程序必须检查行计数,以确保在向用户显示成功反馈之前实际更新了预期的行数。