【问题标题】:SQL Server NOLOCK and joinsSQL Server NOLOCK 和连接
【发布时间】:2010-09-24 01:02:44
【问题描述】:

背景:我想运行一个性能关键型查询,我不关心脏读。

我的问题是;如果我使用连接,是否也必须在这些连接上指定 NOLOCK 提示?

例如;是:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID

相当于:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID

或者我是否需要在连接上指定(NOLOCK) 提示以确保我没有锁定连接的表?

【问题讨论】:

    标签: sql sql-server nolock


    【解决方案1】:

    我不会解决READ UNCOMMITTED 的论点,只是您最初的问题。

    是的,您在连接的每个表上都需要WITH(NOLOCK)。不,您的查询不一样。

    试试这个练习。开始一个事务并在 table1 和 table2 中插入一行。不要提交或回滚事务。此时您的第一个查询将成功返回并包含未提交的行;您的第二个查询不会返回,因为 table2 上没有 WITH(NOLOCK) 提示。

    【讨论】:

    • 可以确认使用 SQL Server 2016 仍然是这种情况。
    【解决方案2】:

    我很确定您需要为查询中的每个 JOIN 指定 NOLOCK。但我的经验仅限于 SQL Server 2005。

    当我查找 MSDN 只是为了确认时,我找不到任何确定的东西。下面的陈述似乎让我觉得,对于 2008 年,您上面的两个陈述是等效的,但在 2005 年情况并非如此:

    [SQL Server 2008 R2]

    所有锁定提示都会传播到查询计划访问的所有表和视图,包括视图中引用的表和视图。此外,SQL Server 还会执行相应的锁一致性检查。

    [SQL Server 2005]

    在 SQL Server 2005 中,所有锁定提示都会传播到视图中引用的所有表和视图。此外,SQL Server 还会执行相应的锁一致性检查。

    另外,请注意 - 这适用于 2005 年和 2008 年:

    如果查询计划未访问表,则忽略表提示。这可能是由于优化器选择根本不访问该表,或者是因为访问的是索引视图。在后一种情况下,可以通过使用OPTION (EXPAND VIEWS) 查询提示来阻止访问索引视图。

    【讨论】:

    • @In Sane:有趣...谢谢...我假设将其包含在 JOINS 中不会造成任何伤害,即使它不是完全必要的?正如您所提到的,关于 NOLOCK 的文档非常稀疏;我自己很难找到任何结论性的东西。
    • @InSane:你从哪里得到这些信息的?这似乎与公认的答案背道而驰。
    • @notfed - 参考技术网链接technet.microsoft.com/en-us/library/ms187373(v=sql.105).aspx - 您可以在顶部更改数据库版本,以比较不同版本的数据库的同一篇文章
    • 2005 年的文本谈到了 VIEWS。因此,如果您执行“使用 (nolock) 从 myview 执行”,那么它表示 nolock 会传播到 myview 中涉及的所有表和视图(您可以在那里有 10 个连接)。不确定 2008 年文本的确切含义,因为它除了视图之外还添加了“由查询计划访问”。
    【解决方案3】:

    两者都没有。您将隔离级别设置为READ UNCOMMITTED,这总是比给出单独的锁定提示要好。或者,更好的是,如果您关心consistency 之类的细节,请使用snapshot isolation

    【讨论】:

    • @Remus:我不确定是否可以在我的情况下使用 READ UNCOMMITTED,因为我正在通过 NHibernate 访问连接以执行特殊的原始 ADO.NET 调用;这可以在查询中内联指定,还是会遵守 NHibernate 事务中存在的事务级别?
    • 将调用包装在using (TransactionScope scope=new TransactionScope(..., TransactionOptions) {...} 中并在选项上设置IsolationLevelmsdn.microsoft.com/en-us/library/…
    • @Remus:不幸的是,事务管理的处理水平比这要高得多,所以这也不是一个选择。
    • 我明白了。然后回答您的问题:NOLOCK 是一个 table 提示,因此它适用于要添加到的行集(表、视图、TVF 等)。如果您在一个查询中加入了多个行集,则每个行都需要自己的 NOLOCK 提示。
    • 但是你考虑过快照隔离吗? ALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON;。结果是惊人的,因为所有正常的已提交读取都变成了快照读取,无锁但一致。成本增加tempdb负载:msdn.microsoft.com/en-us/library/ms175492.aspx
    猜你喜欢
    • 2016-03-08
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多