Der NOLOCK-Hinweis ändert die Reihenfolge der zurückgegebenen Datensätze


10

Es gibt einen Clustered - Index auf einem Tisch ClientFeld LastName.

Wenn ich einfach alle Datensätze aus der Tabelle speichere, werden sie in alphabetischer Reihenfolge angezeigt, sofern nicht (nolock)wie in der betreffenden Abfrage ein Hinweis verwendet wird. Dieser Hinweis ändert die Reihenfolge der Datensätze. Sollte es?. Ich bin mir sicher, dass keine andere Sitzung eine offene Transaktion mit den Änderungen an dieser Tabelle hat (zumindest werden sp_who2mir keine angezeigt).

Wie kann der Unterschied in der Reihenfolge erklärt werden?

Zusätzliche Informationen aus Kommentaren:

  1. Es gibt keine Bestellung von. Sollte ein nicht gruppierter Index die Reihenfolge erzwingen?

  2. Die Abfragen geben auch dann noch eine andere Reihenfolge zurück, wenn ein Indexhinweis verwendet wird, der einen Clustered-Index angibt. Sollten Sie? Ich frage mich, warum nolocksich die Reihenfolge der zurückgegebenen Datensätze ändert, ohne dass die Pläne sichtbar geändert werden.

  3. Ich habe ein WinDiff auf ihnen gemacht - dasselbe mit Ausnahme von [dem] (nolock)[ Abfragehinweis ].


21
Der Hinweis ändert die Reihenfolge nicht - da es keine Reihenfolge gibt, die geändert werden könnte
a_horse_with_no_name

Antworten:


47

Das Auftreten einer geordneten Ergebnismenge ohne ORDER BYKlausel resultiert häufig aus einem Scan, bei dem Zeilen in Indexreihenfolge abgerufen werden. Ein Grund, warum ein Scan in Indexreihenfolge im Allgemeinen unter der Standardisolationsstufe ausgewählt READ COMMITTEDwird, besteht darin, dass die Wahrscheinlichkeit unerwünschter Parallelitätsanomalien verringert wird, z. B. das mehrfache Auftreten derselben Zeile oder das vollständige Überspringen einiger Zeilen. Dies wird an mehreren Stellen detailliert beschrieben, einschließlich in dieser Artikelserie über Isolationsstufen.

Mit einem NOLOCKTabellenhinweis wird dieses Verhalten gelockert, und der Zugriff auf die Tabelle erfolgt unter der toleranteren READ UNCOMMITTEDIsolationsstufe, die Daten in Zuordnungsreihenfolge anstelle der Indexreihenfolge scannen kann . Wie in diesem Link beschrieben, bleibt die Entscheidung, ob ein Scan der Zuordnungsreihenfolge oder der Indexreihenfolge verwendet werden soll, der Speicher-Engine überlassen. Diese Auswahl kann zwischen Ausführungen ohne Änderung des Abfrageplans geändert werden .

Dies mag sehr abstrakt klingen, kann jedoch mit einigen Abfragen mithilfe nicht dokumentierter Funktionen für die AdventureWorks2012-Datenbank einfacher demonstriert werden .

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);

Abfrageergebnisse

Die Anfragen wurden mit geringfügigen Änderungen von Paul White ausgeliehen .

Um ganz klar zu sein, handelt es sich bei dieser Antwort um das Erscheinungsbild einer geordneten Ergebnismenge. Es gibt keine garantierte Präsentationsreihenfolge ohne Top-Level ORDER BY.

Ein Scan der Zuordnungsreihenfolge kann unter verschiedenen anderen Umständen erfolgen, z. B. wenn eine Sperre auf Tabellenebene erworben wird oder sich die Datenbank im schreibgeschützten Modus befindet. Parallelität kann auch die Reihenfolge beeinflussen, in der die Daten zurückgegeben werden. Der entscheidende Punkt ist, dass ORDER BYdie Reihenfolge, in der die Daten zurückgegeben werden , ohne Design im Laufe der Zeit variieren kann.


7
Schön, viel spezifischer als mein unbeachteter Versuch. Der springende Punkt ist natürlich in Ihren letzten beiden Absätzen. "Warum" spielt am Ende keine Rolle. Vielleicht haben Sie mehr Glück, diesen Akkord zu schlagen als ich.
Aaron Bertrand

11

James hat gut erklärt, wie das funktioniert, aber ich möchte nur eines wiederholen: Wenn Sie keine Ordnungsfunktion verwenden, ist die Reihenfolge der Zeilen in der Ergebnismenge undefiniert . Wenn Sie eine bestimmte Reihenfolge benötigen, verwenden Sie eine explizite order byKlausel. Wenn Sie diese nicht angeben, sagen Sie im Grunde genommen "Die Reihenfolge ist mir überhaupt egal" und nicht "Sortieren nach dem Clustered-Index".


11

Wenn ich einfach alle Datensätze aus der Tabelle entleere

... dann sollten Sie keine Bestellung erwarten. Tatsächlich kann dieselbe Abfrage, die mehrmals ausgeführt wird, ohne Vorwarnung in einer anderen Reihenfolge wiedergegeben werden. Der Grund dafür ist, dass Ihre beiden Abfragen - die höchstwahrscheinlich aufgrund des unterschiedlichen Abfragetextes und nicht aufgrund des Hinweises "unterschiedliche" Abfragen sind - unterschiedliche Ausführungspläne haben (und der Unterschied kann subtil sein, z. B. ein Iterator, der in gleich aussieht beide Pläne, hat aber ordered: truenur eine oder eine sehr unterschiedliche Anzahl geschätzter Zeilen, da eine vor einer größeren Datenänderung kompiliert wurde). Es könnte auch sein, dass ein Zuordnungsreihenfolge-Scan durchgeführt wird, wie James in seiner Antwort richtig dargelegt hat.

Da Sie eine Abfrage ohne ORDER BYausführen, schließt SQL Server auf jeden Fall, dass Sie sich nicht um die Reihenfolge kümmern, und ermittelt daher den effizientesten Weg, um die Zeilen zurückzugeben (wenn Sie dies nicht tun, ist die Reihenfolge nicht wichtig ).

Lassen Sie mich das ganz klar machen:

Wenn Sie eine bestimmte Bestellung wünschen oder erwarten, fügen Sie eine ORDER BY-Klausel hinzu

Das ist schon mal aufgetaucht:

Und ich habe darüber gebloggt:

Hier ist ein Zitat aus letzterem, das wiederholt, was ich gesagt habe, um Ihren Kommentar zur Verwendung eines Indexhinweises anstelle einer ORDER BYKlausel anzusprechen :

Selbst im Fall eines angedeuteten Index wird der Index verwendet (wenn möglich, sonst in den meisten Fällen ein Fehler). Nur weil der Index verwendet wird, bedeutet dies nicht, dass die Ergebnisse sortiert nach den Schlüsseln zurückgegeben werden dieser Index. Sie benötigen noch eine ORDER BY, um die Sortierung nach den Indexschlüsseln sicherzustellen.

Conor Cunningham - ein ziemlich kluger Kerl, der direkt für vieles verantwortlich ist, was SQL Server tut, wenn es eine Abfrage für Sie verarbeitet - hat auch hier darüber gebloggt:

Bitte lesen Sie etwas und fügen Sie dann eine ORDER BYKlausel zu Ihren Abfragen hinzu, bevor Sie sich über eine andere oder unerwartete Sortierung beschweren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.