Vermeiden Sie den Sortieroperator im Indexplan

8

Ich habe zwei Tabellen [LogTable] und [LogTable_Cross].

Im Folgenden finden Sie das Schema und das Skript zum Auffüllen:

%Vor%

Ich möchte alle diese Logs (aus LogTable) auswählen, die Benutzer-ID (Benutzer-ID wird von Kreuztabelle LogTable_Cross) mit Datesent Desc.

%Vor%

Nach dem Ausführen dieser Abfrage ist hier mein Ausführungsplan:

Wie Sie sehen können, kommt ein Sortieroperator in die Rolle, und das sollte wahrscheinlich wegen der folgenden Zeile "ORDER BY DateSent DESC"

sein

Meine Frage ist, warum dieser Sortieroperator in den Plan kommt, obwohl ich den folgenden Index auf die Tabelle angewendet habe

%Vor%

Wenn ich andererseits den Join entferne und die Abfrage auf diese Weise schreibe:

%Vor%

Der Plan ändert sich zu

d. h. Sortieroperator wird entfernt und der Plan zeigt an, dass meine Abfrage meinen nicht gruppierten Index verwendet.

Das ist also eine Möglichkeit, den Operator "Sortieren" im Plan für meine Abfrage zu entfernen, selbst wenn ich Join verwende.

BEARBEITEN :

Ich ging weiter und begrenzte den "Max Parallelitätsgrad" auf 1

Lief die folgende Abfrage erneut ab:

%Vor%

und der Plan hat immer noch diesen Sortieroperator:

Bearbeiten 2

Auch wenn ich den folgenden Index wie vorgeschlagen habe:

%Vor%

Der Plan hat immer noch den Sortieroperator:

    
Raghav 19.04.2017, 08:54
quelle

3 Antworten

2

Die zweite Abfrage von Ihnen enthält die UserId-Bedingung nicht und daher ist es keine äquivalente Abfrage. Der Grund, warum die erste Abfrage nicht von Ihren Indizes in LogTable abgedeckt wird, ist die Tatsache, dass UserId nicht in ihnen vorhanden ist (und Sie müssen auch den Join ausführen). Daher muss SQL Server den Tabellen beitreten (Hash Join, Merge Join oder Nested-Loop Join). SQL Server wählt den Hash-Join korrekt aus, da die Zwischenergebnisse groß sind und nicht gemäß der LogID sortiert sind. Wenn Sie ihnen das Zwischenergebnis sortiert nach der LogID (Ihre zweite Bearbeitung) geben, dann verwendet er Merge Join, aber sortieren nach dem DateSend ist stil erforderlich. Die einzige Lösung ohne Sortierung ist das Erstellen einer indizierten materialisierten Ansicht:

%Vor%

Die Ansicht muss mit noexpand-Hinweis verwendet werden, damit der Optimierer den CIX_vCustomerOrders-Index finden kann:

%Vor%

Diese Abfrage ist eine äquivalente Abfrage für Ihre erste Abfrage. Sie können die Richtigkeit überprüfen, wenn Sie die folgende Zeile einfügen:

%Vor%

dann gibt meine Abfrage immer noch das korrekte Ergebnis (10000 Zeilen) zurück, Ihre zweite Abfrage gibt jedoch 10001 Zeilen zurück. Sie können versuchen, einige andere Zeilen zu löschen oder einzufügen, und die Ansicht ist immer noch auf dem neuesten Stand und Sie erhalten korrekte Ergebnisse von meiner Abfrage.

    
Radim Bača 19.04.2017 14:03
quelle
1

Sie haben eine Sortieroperation, wenn Sie den Join haben wegen der Parallelität in den vorherigen Schritten. Wenn SQL Server die Datensätze in mehreren Threads verarbeitet, wird die Reihenfolge nicht mehr bestimmt. Jeder Thread schiebt die Ergebnisse einfach an das nächste Element in der Pipeline (Hash-Match in Ihrem Fall).

Da die Reihenfolge nicht festgelegt ist und Sie eine Bestellung anfordern, muss SQL Server das Ergebnis sortieren.

Sie können versuchen, den MAXDOP = 1 -Hinweis hinzuzufügen, um zu erzwingen, dass SQL Server die Abfrage nur mit einem Thread ausführt. Dies kann in diesem Fall hilfreich sein, kann aber auch zu Leistungseinbußen führen.

Die zweite Abfrage kann mit einem Index-Scan erfüllt werden, und der Index ist geordnet und die Reihenfolge ist die gleiche wie die angeforderte. Die Datensätze (Schlüssel) im Index werden per Definition sortiert. SQL Server vermutete, dass das Ausführen der Abfrage in einem Thread und das einfache Lesen der Daten mithilfe des Index vorteilhafter ist als das Lesen der Daten mithilfe mehrerer Threads und deren späterer Sortierung.

    
Pred 19.04.2017 09:14
quelle
1

Ich denke, der Grund könnte hier sein:

%Vor%

Ihre Tabelle enthält keinen Index für LogID. Diese Spalte wird jedoch für JOIN verwendet. INCLUDE LogID bedeutet nicht, dass dieser Index nach LogID durchsucht werden kann. Dies ist nur ein kleines bisschen schneller, wenn Sie nach UserId suchen und Sie die entsprechende LogID brauchen (Sie müssen das nicht nachsehen)

Wenn Sie sich über LogID anmelden, sollte es am schnellsten sein, die Liste vorher zu sortieren, da kein Index verfügbar ist ...

Wenn Platz keine Rolle spielt (und Performance einfügen / aktualisieren, können Sie einen Index umgekehrt hinzufügen, aber ich würde vorschlagen, einen zweispaltigen Clusterschlüssel mit zu verwenden LogId an der ersten Position und - falls erforderlich - ein einfacher nicht gruppierter Index für UserId.

    
Shnugo 19.04.2017 09:29
quelle