NOLOCKヒントは、返されるレコードの順序を変更します


11

テーブルClientフィールドにクラスター化インデックスがありますLastName

テーブルからすべてのレコードを単純にダンプすると、(nolock)問題のクエリのようにヒントが使用されていない限り、レコードはアルファベット順に表示されます。そのヒントは、レコードの順序を変更します。それをすべきですか?他のどのセッションにも、そのテーブルへの変更を伴うオープントランザクションsp_who2がないことは確かです(少なくとも私には何も表示されていません)。

順序の違いはどのように説明できますか?

コメントから引き出された追加情報:

  1. による注文はありません。非クラスター化インデックスは順序を強制する必要がありますか?

  2. クラスター化インデックスを指定するインデックスヒントを使用する場合でも、クエリは異なる順序を返します。彼らはすべきですか?nolock返されたレコードの順序が、計画の目に見える変更なしに変更されるのはなぜでしょうか。

  3. 私はそれらに対してWinDiffを行いました-[the] (nolock)[query hint] を除いて同じです。


21
ヒントは順序を変更しません-変更できる順序がないため
a_horse_with_no_name

回答:


47

ORDER BY句なしの順序付けされた結果セットの外観は、多くの場合、インデックス順で行を取得するスキャンの結果です。通常、デフォルトのREAD COMMITTED分離レベルの下でインデックス順スキャンが選択される理由の1つは、同じ行に複数回遭遇したり、一部の行を完全にスキップしたりするなど、不要な同時実行の異常の可能性を減らすためです。これについては、分離レベルに関するこの一連の記事を含め、いくつかの場所で詳しく説明されています。

NOLOCKテーブルヒント、この現象は緩和され、テーブルへのアクセスはより耐性で行われるREAD UNCOMMITTEDことができる分離レベル、割当順にデータをスキャンする代わりに、インデックス順の。そのリンクで説明されているように、割り当て順スキャンとインデックス順スキャンのどちらを使用するかについての決定は、ストレージエンジンに任されています。この選択は、クエリプランを変更せずに、実行間で変わる可能性があります

これは非常に抽象的なように聞こえるかもしれませんが、AdventureWorks2012データベースに対して文書化されていない関数を使用するいくつかのクエリでより簡単に示すことができます

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

クエリ結果

クエリは、Paul Whiteから少し変更して借用しました。

最後に、明確にするために、この答えは順序付けられた結果セットの外観についてです。トップレベルがなければ、保証された表示順序はありませんORDER BY

割り当て順スキャンは、テーブルレベルのロックが取得されたときや、データベースが読み取り専用モードになっているときなど、他のさまざまな状況で発生する可能性があります。並列処理は、データが返される順序にも影響を与える可能性があります。重要な点は、を使用しないORDER BY場合、データが返される順序は設計により時間とともに変化する可能性があるということです。


7
素敵な、私の認められていない試みよりもはるかに具体的です。もちろん、核心は最後の2つの段落にあります。「なぜ」は、結局はそれほど重要ではありません。多分あなたは私がしたよりもそのコードを打つ幸運があるでしょう。
アーロンバートランド

12

テーブルからすべてのレコードを単にダンプすると

...その後、注文を期待するべきではありません。実際、同じクエリを複数回実行すると、警告なしに別の順序で返される可能性があります。その理由は、ヒントではなくクエリテキストが異なるために「異なる」クエリである可能性が高い2つのクエリが異なる実行プランを持っているためです(そして、違いは微妙な場合があります(同じように見えるイテレータなど)。両方の計画がありますがordered: true、1つしかありません。または、大きなデータ変更の前に1つがコンパイルされているため、推定行数が大幅に異なります)。ジェームズが彼の回答で正しく概説したように、割り当て順序スキャンが行われている可能性もあります。

いずれの場合でも、を使用せずORDER BYにクエリを実行しているため、SQL Serverは順序を気にしないと推測し、オフになって行を返す最も効率的な方法を決定します(そうしなければ、順序を気にしません。 )。

これを明確にしておきます。

特定の順序が必要または期待される場合は、ORDER BY句を追加します

これは以前に発生しました:

そして私はそれについてブログに書いています:

後者の引用は、ORDER BY節の代わりにインデックスヒントを使用することについてのコメントに対処するために私が言ったことを繰り返します。

ヒント付きインデックスの場合でも、インデックスが使用されます(可能な場合は、ほとんどの場合はエラーです)。ただし、インデックスが使用されているからといって、結果がキーでソートされて返されるわけではありません。そのインデックス。ORDER BYインデックスキーで確実にソートするために、まだ必要です。

Conor Cunningham-かなり賢い人で、SQL Serverがクエリを処理するときにSQL Serverが行うことの多くに直接責任を負っています-についてブログでも書いています。

いくつかの読み取りを行ってORDER BYから、クエリに句を追加してから、別のソートまたは予期しないソートについて文句を言ってください。


11

ジェームズはこれがどのように機能するかをうまく説明しましたが、私はただ一つ繰り返します:順序付け関数を使用しない限り、結果セット内の行の順序はundefinedです。特定の順序付けが必要な場合は、明示的なorder by句を使用します。指定しない場合は、「クラスター化インデックスで順序付けする」ではなく、基本的に「順序をまったく気にしません」と言います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.