Beim Betrachten eines Ausführungsplans einer langsam laufenden Abfrage stellte ich fest, dass einige der Knoten eine Indexsuche und einige eine Indexsuche sind.
Was ist der Unterschied zwischen Indexsuche und Indexsuche?
Welches ist besser?
Wie wählt SQL eine über die andere aus?
Mir ist klar, dass dies 3 Fragen sind, aber ich denke, dass die Beantwortung der ersten die anderen erklärt.
Antworten:
Kurzfassung: Suchen ist viel besser
Weniger kurze Version: Die Suche ist im Allgemeinen viel besser, aber viele Suchvorgänge (z. B. aufgrund eines schlechten Abfrageentwurfs mit unangenehmen korrelierten Unterabfragen oder weil Sie viele Abfragen in einer Cursoroperation oder einer anderen Schleife ausführen) können schlechter sein als ein Scan, insbesondere wenn Ihre Abfrage möglicherweise Daten aus den meisten Zeilen in der betroffenen Tabelle zurückgibt.
Es ist hilfreich, die gesamte Familie für Datenfindungsvorgänge abzudecken, um die Auswirkungen auf die Leistung zu verstehen.
Tabellenscans: Da für Ihre Abfrage überhaupt keine Indizes relevant sind, muss der Planer einen Tabellenscan verwenden, bei dem jede Zeile überprüft wird. Dies kann dazu führen, dass jede Seite, die sich auf die Daten der Tabelle bezieht, von der Festplatte gelesen wird, was häufig der schlimmste Fall ist. Beachten Sie, dass bei einigen Abfragen auch dann eine Tabellensuche durchgeführt wird, wenn ein nützlicher Index vorhanden ist. Dies liegt normalerweise daran, dass die Daten in der Tabelle so klein sind, dass das Durchlaufen der Indizes mühsamer ist (wenn dies der Fall ist, würde man das erwarten) Planen Sie, Änderungen vorzunehmen, wenn die Daten wachsen, vorausgesetzt, das Maß für die Selektivität des Index ist gut.
Index-Scans mit Zeilensuchen: Wenn kein Index gefunden wird, der direkt für eine Suche verwendet werden kann, aber ein Index mit den richtigen Spalten vorhanden ist, kann ein Index-Scan verwendet werden. Wenn Sie beispielsweise eine große Tabelle mit 20 Spalten und einem Index für Spalte1, Spalte2, Spalte3 haben und das Problem auftritt
SELECT col4 FROM exampletable WHERE col2=616
, ist es in diesem Fallcol2
besser , den abzufragenden Index zu scannen, als die gesamte Tabelle zu scannen. Sobald übereinstimmende Zeilen gefunden wurden, müssen die Datenseiten gelesen werden, um col4 für die Ausgabe (oder das weitere Verknüpfen) abzurufen. Dies ist die Stufe der "Lesezeichensuche", wenn Sie sie in Abfrageplänen sehen.Index-Scans ohne Zeilensuche: Wenn das obige Beispiel verwendet wurde,
SELECT col1, col2, col3 FROM exampletable WHERE col2=616
ist der zusätzliche Aufwand zum Lesen von Datenseiten nicht erforderlich: Sobald übereinstimmende Indexzeilencol2=616
gefunden wurden, sind alle angeforderten Daten bekannt. Aus diesem Grund werden manchmal Spalten angezeigt, die nie durchsucht werden, aber wahrscheinlich zur Ausgabe angefordert werden und am Ende von Indizes hinzugefügt werden. Dadurch können Zeilensuchen gespart werden. Wenn Sie einem Index aus diesem Grund und nur aus diesem Grund Spalten hinzufügen, fügen Sie diese mit derINCLUDE
Klausel hinzu, um der Engine mitzuteilen, dass das Indexlayout für Abfragen auf der Grundlage dieser Spalten nicht optimiert werden muss (dies kann Aktualisierungen dieser Spalten beschleunigen). . Indexprüfungen können auch aus Abfragen ohne Filterklauseln resultieren:SELECT col2 FROM exampletable
Durchsucht diesen Beispielindex anstelle der Tabellenseiten.Index-Suchvorgänge (mit oder ohne Zeilensuche) : Bei einem Suchvorgang wird nicht der gesamte Index berücksichtigt. Für die Abfrage kann
SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567
die Abfrage-Engine die erste übereinstimmende Zeile finden, indem sie eine baumbasierte Suche im Index durchführt.c1
Anschließend kann sie den Index nacheinander durchsuchen, bis das Ende des Bereichs erreicht ist (dies gilt auch für eine Abfrage) fürc1=1234
wie könnte es viele Zeilen sein , die Bedingung selbst für einen passenden=
Betrieb). Dies bedeutet, dass nur relevante Indexseiten (plus einige für die erste Suche erforderliche) anstelle jeder Seite im Index (oder in der Tabelle) gelesen werden müssen.Clustered-Indizes: Bei einem Clustered-Index werden die Tabellendaten nicht in einer separaten Heap-Struktur, sondern in den Blattknoten dieses Index gespeichert. Dies bedeutet, dass nach dem Suchen von Zeilen mit diesem Index keine zusätzlichen Zeilensuchen erforderlich sind, unabhängig davon, welche Spalten benötigt werden [es sei denn, Sie haben Off-Page-Daten wie
TEXT
Spalten oderVARCHAR(MAX)
Spalten mit langen Daten].Aus diesem Grund können Sie nur einen Clustered-Index haben [1] . Der Clustered-Index ist Ihre Tabelle, anstatt eine separate Heap-Struktur zu haben. Wenn Sie also einen [2] verwenden, wählen Sie die Position sorgfältig aus, um den maximalen Gewinn zu erzielen.
Beachten Sie auch, dass der Clustered-Index als "Clustering-Schlüssel" für die Tabelle gilt und in jedem Nicht-Clustered-Index für die Tabelle enthalten ist, sodass ein Wide-Clustered-Index im Allgemeinen keine gute Idee ist.
[1] Sie können effektiv mehrere Clustered-Indizes definieren, indem Sie Nicht-Clustered-Indizes definieren, die jede Spalte in der Tabelle abdecken oder einschließen. Dies ist jedoch wahrscheinlich eine Verschwendung von Speicherplatz und hat Auswirkungen auf die Schreibleistung das musst du wirklich.
[2] Wenn ich sage „ wenn Sie einen Clustered - Index verwenden“, merken Sie, dass es in der Regel , dass Sie empfohlen tun haben auf jedem Tisch ein. Wie bei allen Faustregeln gibt es Ausnahmen. Tabellen, die nur Masseneinfügungen und ungeordnete Lesevorgänge sehen (Staging-Tabellen für ETL-Prozesse vielleicht), sind das häufigste Indikatorbeispiel.
Zusätzlicher Punkt: Unvollständige Scans:
Es ist wichtig zu bedenken, dass abhängig vom Rest der Abfrage ein Tabellen- / Index-Scan möglicherweise nicht die gesamte Tabelle scannt - wenn die Logik dies zulässt, kann der Abfrageplan möglicherweise dazu führen, dass die Abfrage vorzeitig abgebrochen wird. Das einfachste Beispiel hierfür ist
SELECT TOP(1) * FROM HugeTable
: Wenn Sie sich den Abfrageplan dafür ansehen, werden Sie feststellen, dass nur eine Zeile vom Scan zurückgegeben wurde, und wenn Sie sich die E / A-Statistiken (SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable
) ansehen, werden Sie feststellen, dass sie nur eine sehr kleine Zahl lesen von Seiten (vielleicht nur eine).Dasselbe kann passieren, wenn das Prädikat einer
WHERE
oderJOIN ... ON
-Klausel gleichzeitig mit dem Scan ausgeführt werden kann, bei dem es sich um die Quelle der Daten handelt. Der Abfrageplaner / -ausführer kann manchmal sehr geschickt sein, Prädikate in Richtung der Datenquellen zurückzuschieben, um auf diese Weise das vorzeitige Beenden von Überprüfungen zu ermöglichen (und manchmal können Sie Abfragen geschickt neu anordnen, um dies zu unterstützen!). Während die Daten gemäß den Pfeilen in der Standardanzeige des Abfrageplans von rechts nach links fließen, wird die Logik von links nach rechts ausgeführt, und jeder Schritt (von rechts nach links) wird nicht unbedingt vollständig ausgeführt, bevor der nächste beginnen kann. Wenn Sie im obigen einfachen Beispiel jeden Block im Abfrageplan als Agent betrachtenSELECT
, fragt derTOP
Agent den Agenten nach einer Zeile, die wiederum den fragtTABLE SCAN
Agent für einen, dannSELECT
fragt der Agent nach einem anderen, aber derTOP
Agent weiß, dass es keinen Grund gibt, sich nicht einmal die Mühe zu machen, den Tabellenleser zu fragenSELECT
. Viele Operationen blockieren diese Art der Optimierung natürlich so oft in kompliziertere Beispiele eine Tabelle / Index - Scan wirklich nicht jede Zeile gelesen, aber darauf achten, nicht zu dem Schluss zu springen , dass jeder Scan eine teure Operation sein muss.quelle
Im Allgemeinen sind Suchvorgänge gut, Scans sind schlecht.
Suchvorgänge sind der Ort, an dem die Abfrage den Index effektiv nutzen und die benötigten Zeilen finden kann.
Bei Scans durchsucht die Abfrage den gesamten Index, um herauszufinden, was sie benötigt.
Wie wählt SQL aus? Tief in den Interna des Abfrageoptimierers wird die Entscheidung basierend auf Ihrer Abfrage und den verfügbaren Indizes sowie den statistischen Informationen getroffen, die diesen Indizes zugeordnet sind.
Es gibt ein paar Bücher zu lesen, die hier von Interesse sein könnten - beide im Red-Gate-Buchladen unter http://www.red-gate.com/community/books/
quelle
Wenn Sie sich mit dem Thema befassen möchten, ist SQL Server Execution Plans von Grant Fritchey (zumindest für mich) ein sehr hilfreiches Buch, das hier bei RedGate kostenlos erhältlich ist .
Wenn Sie eine Frage wie haben
SQL Server verwendet wahrscheinlich einen Index-Scan, da alle Zeilen durchsucht werden müssen, um die erforderlichen Ergebnisse anzuzeigen.
Andererseits,
wird sicherlich zu einer Indexsuche führen. SQL Server verwendet die B-Tree-Struktur des myID-Index und das Abrufen der richtigen Zeile ist viel schneller.
quelle
Andere haben die Unterschiede zwischen Suchen und Scannen gut genug definiert. In diesem Fall sollten Ihre Abfrage selbst und der Ausführungsplaner die Informationen enthalten, die Sie benötigen, um zu sehen, welche Werte als Prädikate (Filter) für die Abfrage in jedem Teil verwendet werden. In der Regel empfiehlt es sich, nicht gruppierte Indizes zu Fremdschlüsseln hinzuzufügen. Abhängig von den Anwendungsfällen im Programmcode möchten Sie möglicherweise auch zusätzliche mehrspaltige Indizes oder eingeschlossene Spaltenindizes erstellen. Mit der hier vorgestellten Terminologie liefert eine Google-Suche ansehnliche Ergebnisse für Beispiele.
Angenommen, Ihr Code fragt nach Spalte A und Spalte B für bestimmte Filter ab. Sie möchten jedoch auch die Werte von Spalte C und Spalte E zurückgeben. Möglicherweise möchten Sie einen Index für Spalte A und B mit INCLUDE erstellen Option mit den Spalten C und E. Auf diese Weise gibt eine einzelne Indexsuche alles zurück, was Sie benötigen, da keine Suche erforderlich ist, um die anderen Werte (C und E) in derselben Zeile abzurufen.
quelle