在嵌套查询中放置WITH(NOLOCK)

时间:2013-08-16 13:43:29

标签: sql sql-server sql-server-2008 tsql

在以下查询中,我将WITH(NOLOCK)放在哪里?

SELECT *
FROM   (SELECT *
        FROM   (SELECT *
                FROM   (SELECT *
                        FROM   (SELECT *
                                FROM   dbo.VBsplit(@mnemonicList, ',')) a) b
                       JOIN dct
                         ON dct.concept = b.concept
                WHERE  b.geo = dct.geo) c
               JOIN dct_rel z
                 ON c.db_int = z.db_int) d
       JOIN rel_d y
         ON y.rel_id = d.rel_id
WHERE  y.update_status = 0
GROUP  BY y.rel_id,
          d.concept,
          d.geo_rfa 

3 个答案:

答案 0 :(得分:10)

您不应将NOLOCK放在该查询中的任何位置。如果你试图阻止读者阻止作者,那么更好的选择是READ COMMITTED SNAPSHOT。当然,您应该阅读此内容,就像您应该在将NOLOCK盲目地投入查询之前阅读VBSplit()一样:

此外,由于您使用的是SQL Server 2008,因此您可能应该使用表值参数替换CREATE TYPE dbo.Strings AS TABLE(Word NVARCHAR(900) PRIMARY KEY); 函数 - 这将比分割字符串更有效,即使函数已烘焙在CLR中暗示。

首先,创建一个可以容纳相应字符串的表类型。我将假设该列表保证是唯一的,并且没有单独的助记词可以是> 900个字符。

CREATE PROCEDURE dbo.Whatever
  @Strings dbo.Strings READONLY
AS 
BEGIN
  SET NOCOUNT ON;
  SET TRANSACTION ISOLATION LEVEL --<choose wisely>;

  SELECT -- please list your columns here instead of *
    FROM @Strings AS s
    INNER JOIN dbo.dct -- please always use proper schema prefix
    ON dct.concept = s.Word
    ...
END
GO

现在,您可以创建一个过程,该过程采用此类型的参数,并在一个位置设置您选择的隔离级别:

{{1}}

现在你可以简单地从你的应用程序中传递一个集合(例如DataTable),无论是C#还是其他什么,而且根本不需要组装或解构一个混乱的逗号分隔列表。

答案 1 :(得分:3)

因为问题确实存在,“我应该把NOLOCK放在哪里”。我不打算讨论使用OR重新格式化查询与更好的连接。我将回答这个问题。

我绝不打算说这是更好的方式,或者说其他答案都不好。另一个答案解决了实际问题。我只是打算显示确切地放置锁定提示的位置,问题是

SELECT *
FROM   (SELECT *
        FROM   (SELECT *
                FROM   (SELECT *
                        FROM   (SELECT *
                                FROM   dbo.VBsplit(@mnemonicList, ',')) a) b
                       JOIN dct WITH (NOLOCK) --        <---
                         ON dct.concept = b.concept
                WHERE  b.geo = dct.geo) c
               JOIN dct_rel z WITH (NOLOCK) --        <---
                 ON c.db_int = z.db_int) d
       JOIN rel_d y WITH (NOLOCK) --        <---
         ON y.rel_id = d.rel_id
WHERE  y.update_status = 0
GROUP  BY y.rel_id,
          d.concept,
          d.geo_rfa 

答案 2 :(得分:2)

像这样,使用最整洁的方法。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT * FROM (SELECT * FROM 
(SELECT * FROM (SELECT * FROM 
(SELECT * FROM dbo.VBsplit(@mnemonicList,',')) a ) b 
JOIN dct ON dct.concept = b.concept WHERE b.geo = dct_variable.geo_rfa) c
JOIN dct_rel z ON c.db_int = z.db_int) d
JOIN rel_d y ON y.rel_id = d.rel_id
WHERE y.update_status = 0
GROUP BY y.rel_id,d.concept,d.geo_rfa
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

但是,除非您在活动数据库上将其用于报告目的,否则启用脏读可能不是最好的方法。

编辑为(NOLOCK)本身不会被弃用,除非此处描述:http://technet.microsoft.com/en-us/library/ms143729.aspx