1

次のクエリでは、どこに配置し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 
4

3 に答える 3

10

NOLOCKそのクエリのどこにも入れないでください。リーダーがライターをブロックするのを防ごうとしている場合、はるかに優れた代替手段はREAD COMMITTED SNAPSHOTです。NOLOCKもちろん、やみくもにクエリに投げ込む前に読む必要があるのと同じように、これについて読む必要があります。

また、SQL Server 2008 を使用しているため、おそらくVBSplit()関数をテーブル値パラメーターに置き換える必要があります。これは、関数が暗黙のように CLR で焼き付けられている場合でも、文字列を分割するよりもはるかに効率的です。

まず、適切な文字列を保持できるテーブル型を作成します。リストが一意であることが保証されており、個々のニーモニック ワードが 900 文字を超えることはできないと仮定します。

CREATE TYPE dbo.Strings AS TABLE(Word NVARCHAR(900) PRIMARY KEY);

これで、このタイプのパラメーターを受け取り、選択した分離レベルを 1 つの場所に設定するプロシージャーを作成できます。

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

これで、コレクション (DataTable など) をアプリ (C# など) から簡単に渡すことができるようになり、複雑なコンマ区切りのリストを組み立てたり分解したりする必要がまったくなくなりました。

于 2013-08-16T13:50:11.450 に答える
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 
于 2013-08-16T14:48:18.553 に答える
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として編集。

于 2013-08-16T13:48:15.087 に答える