Indexsuche vs Index-Scan

64

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.

Greg
quelle
6
Sie haben eine nette Referenz auf Use-the-Index-Luke .
Marian
7
Nicht alle Scans sind schlecht - manchmal ist dies die effizienteste Methode, um die Abfrage zu erfüllen. Beachten Sie auch, dass nicht alle Suchvorgänge Suchvorgänge sind - oft handelt es sich tatsächlich um Entfernungsscans, und die Suche gibt nur an, wie sie zum Beginn der Entfernung gelangt ist.
Aaron Bertrand
@AaronBertrand aber wenn es an den Anfang des Bereichs kommt und ihn liest, bedeutet das im Grunde, dass du die Daten trotzdem brauchst. Außerdem sucht es das Ende des Bereichs.
George Polevoy

Antworten:

76

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 Fall col2besser , 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=616ist der zusätzliche Aufwand zum Lesen von Datenseiten nicht erforderlich: Sobald übereinstimmende Indexzeilen col2=616gefunden 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 der INCLUDEKlausel 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 exampletableDurchsucht 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 4567die Abfrage-Engine die erste übereinstimmende Zeile finden, indem sie eine baumbasierte Suche im Index durchführt. c1Anschließend kann sie den Index nacheinander durchsuchen, bis das Ende des Bereichs erreicht ist (dies gilt auch für eine Abfrage) für c1=1234wie 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 TEXTSpalten oder VARCHAR(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 WHEREoder JOIN ... 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 betrachten SELECT, fragt der TOPAgent den Agenten nach einer Zeile, die wiederum den fragtTABLE SCANAgent für einen, dann SELECTfragt der Agent nach einem anderen, aber der TOPAgent weiß, dass es keinen Grund gibt, sich nicht einmal die Mühe zu machen, den Tabellenleser zu fragen SELECT. 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.

David Spillett
quelle
6

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/

  • SQL Server-Ausführungspläne von Grant Fritchey
  • Inside the Query Optimizer von Benjamin Nevarez
  • SQL Server Statistics von Holger Schmeling
Thomas Rushton
quelle
7
Für den gleichen Plan ist ein einzelner Tabellenscan gut, eine Million Suchvorgänge sind schlecht. Ihre erste Aussage ist also nicht ganz richtig.
Marian
Tatsächlich hat die Indexsuche und die Indexsuche jeweils ihre eigene Verwendung. Sie können jedoch nicht sagen, dass eine besser ist als eine andere, OHNE den Kontext der zugrunde liegenden Tabellen und Abfragen. Wenn die Statistiken einer Tabelle ungenau sind, wird der Ausführungsplan in den meisten Fällen als nicht optimal eingestuft, z. B. wenn eine Indexsuche versehentlich gegenüber einer Indexsuche ausgewählt wird und umgekehrt.
Jyao
5

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

SELECT *
FROM myTable

SQL Server verwendet wahrscheinlich einen Index-Scan, da alle Zeilen durchsucht werden müssen, um die erforderlichen Ergebnisse anzuzeigen.

Andererseits,

SELECT *
FROM myTable
WHERE myID = 1

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.

KookieMonster
quelle
Ich weiß nicht, ob ich mit "mit Sicherheit" einverstanden bin - auch wenn ein Index myID als führende Spalte hat, ist eine Suche möglicherweise nicht die optimale Antwort (hängt von vielen Dingen ab, z true in der Customers-Tabelle, aber nicht für customerID in der Orders-Tabelle, wie viele Spalten müssen abgedeckt werden, sind aber nicht im Index usw.).
Aaron Bertrand
Ich glaube nicht, dass diese Antwort wirklich die gestellten Fragen abdeckt.
Zero3
5

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.

Kahn
quelle