Wie funktionieren MySQL-Indizes?

402

Ich bin wirklich interessiert daran, wie MySQL-Indizes funktionieren, insbesondere, wie sie die angeforderten Daten zurückgeben können, ohne die gesamte Tabelle zu scannen.

Ich weiß, dass es kein Thema ist, aber wenn es jemanden gibt, der mir dies ausführlich erklären könnte, wäre ich sehr, sehr dankbar.

good_evening
quelle
Dies ist eine sehr breite Frage. Wenn Sie ein bestimmtes Beispiel für eine Abfrage haben, für die kein Index verwendet wird, und Sie nicht wissen, warum, können Sie es veröffentlichen und die Benutzer helfen möglicherweise.
Hammerite
SELECT * FROM members WHERE id = '1'- Warum funktioniert es mit Index schneller? Was macht dieser Index hier?
good_evening
2
Das sieht aus wie eine Abfrage, die nur einen bestimmten, indizierten Datensatz nachschlägt (möglicherweise durch den Primärschlüssel identifiziert). Der Index beschleunigt dies, da er im Speicher gespeichert ist, die entsprechende Indexzeile angezeigt werden kann und einen Zeiger darauf enthält, wo die tatsächlichen Daten gespeichert sind. So kann MySQL genau an die Stelle in der Tabelle gehen, ohne die Tabelle scannen zu müssen.
Hammerite
Sehr gut danke!
Leichtigkeitsrennen im Orbit

Antworten:

513

Grundsätzlich funktioniert ein Index für eine Tabelle wie ein Index in einem Buch (daher stammt der Name):

Angenommen, Sie haben ein Buch über Datenbanken und möchten Informationen zum Thema Speicher finden. Ohne einen Index (unter der Annahme, dass keine andere Hilfe wie ein Inhaltsverzeichnis vorhanden ist) müssten Sie die Seiten einzeln durchgehen, bis Sie das Thema gefunden haben (das ist a full table scan). Auf der anderen Seite enthält ein Index eine Liste mit Schlüsselwörtern. Sie können also den Index konsultieren und sehen, dass er storageauf den Seiten 113-120, 231 und 354 erwähnt wird. Dann können Sie direkt zu diesen Seiten blättern, ohne zu suchen (das ist eine Suche mit einem Index, etwas schneller).

Wie nützlich der Index sein wird, hängt natürlich von vielen Dingen ab - ein paar Beispiele, die das obige Gleichnis verwenden:

  • Wenn Sie ein Buch über Datenbanken hätten und das Wort "Datenbank" indiziert hätten, würden Sie sehen, dass es auf den Seiten 1-59, 61-290 und 292 bis 400 erwähnt wird. In diesem Fall ist der Index keine große Hilfe und könnte es auch sein Gehen Sie schneller durch die Seiten nacheinander (in einer Datenbank ist dies "schlechte Selektivität").
  • Für ein 10-seitiges Buch macht es keinen Sinn, einen Index zu erstellen, da Sie möglicherweise ein 10-seitiges Buch erhalten, dem ein 5-seitiger Index vorangestellt ist, was einfach albern ist - scannen Sie einfach die 10 Seiten und fertig .
  • Der Index muss auch nützlich sein - es macht im Allgemeinen keinen Sinn, ihn zu indizieren, z. B. die Häufigkeit des Buchstabens "L" pro Seite.
Piskvor verließ das Gebäude
quelle
3
Sie erklären, was es ist, nicht wie es intern technisch funktioniert.
Tutu Kumari
@ Tutu Kumari: Siehe die Überarbeitungen der Frage; Sie können die Antwort auch an die aktuelle Frage anpassen (beachten Sie die verschiedenen Engines und Indextypen - siehe z. B. die Dokumentation hier: dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html )
Piskvor verließ das Gebäude am
259

Das erste, was Sie wissen müssen, ist, dass Indizes eine Möglichkeit sind, das Scannen der vollständigen Tabelle zu vermeiden, um das gewünschte Ergebnis zu erhalten.

Es gibt verschiedene Arten von Indizes, die in der Speicherebene implementiert sind. Daher gibt es keinen Standard zwischen ihnen und sie hängen auch von der von Ihnen verwendeten Speicher-Engine ab.

InnoDB und der B + Tree Index

Für InnoDB ist der häufigste Indextyp der B + Tree-basierte Index, der die Elemente in einer sortierten Reihenfolge speichert. Außerdem müssen Sie nicht auf die reale Tabelle zugreifen, um die indizierten Werte abzurufen, wodurch Ihre Abfrage schneller zurückkehrt.

Das "Problem" bei diesem Indextyp besteht darin, dass Sie nach dem Wert ganz links fragen müssen, um den Index zu verwenden. Wenn Ihr Index also zwei Spalten enthält, z. B. Nachname und Vorname, ist die Reihenfolge, in der Sie diese Felder abfragen , von großer Bedeutung .

Also, gegeben die folgende Tabelle:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

Diese Abfrage würde den Index nutzen:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

Aber der folgende würde nicht

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

Weil Sie first_namezuerst die Spalte abfragen und es nicht die Spalte ganz links im Index ist.

Dieses letzte Beispiel ist noch schlimmer:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

Denn jetzt vergleichen Sie den rechten Teil des Feldes ganz rechts im Index.

Der Hash-Index

Dies ist ein anderer Indextyp, den leider nur das Speicher-Backend unterstützt. Es ist blitzschnell , aber nur dann sinnvoll für die vollständige Lookups, was bedeutet , dass Sie es nicht für Operationen verwenden möchten >, <oder LIKE.

Da es nur für das Speicher-Backend funktioniert, werden Sie es wahrscheinlich nicht sehr oft verwenden. Der Hauptfall, an den ich jetzt denken kann, ist der, bei dem Sie eine temporäre Tabelle im Speicher mit einer Reihe von Ergebnissen aus einer anderen Auswahl erstellen und viele andere Auswahlen in dieser temporären Tabelle mithilfe von Hash-Indizes durchführen.

Wenn Sie ein großes VARCHARFeld haben, können Sie die Verwendung eines Hash-Index bei Verwendung eines B-Baums "emulieren", indem Sie eine weitere Spalte erstellen und einen Hash mit dem großen Wert darauf speichern. Angenommen, Sie speichern eine URL in einem Feld und die Werte sind ziemlich groß. Sie können auch ein Ganzzahlfeld mit dem Namen erstellen url_hashund eine Hash-Funktion wie CRC32oder eine andere Hash-Funktion verwenden, um die URL beim Einfügen zu hashen. Wenn Sie diesen Wert abfragen müssen, können Sie Folgendes tun:

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

Das Problem mit dem obigen Beispiel ist, dass, da die CRC32Funktion einen ziemlich kleinen Hash generiert, viele Kollisionen in den Hash-Werten auftreten. Wenn Sie genaue Werte benötigen, können Sie dieses Problem wie folgt beheben:

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

Es lohnt sich immer noch, Dinge zu hashen, auch wenn die Kollisionszahl hoch ist, da Sie nur den zweiten Vergleich (den ersten) mit den wiederholten Hashes durchführen.

Leider müssen Sie mit dieser Technik immer noch die Tabelle treffen, um das urlFeld zu vergleichen .

Einpacken

Einige Fakten, die Sie jedes Mal berücksichtigen sollten, wenn Sie über Optimierung sprechen möchten:

  1. Der Ganzzahlvergleich ist viel schneller als der Zeichenfolgenvergleich. Dies kann anhand des Beispiels zur Emulation des Hash-Index in veranschaulicht werden InnoDB.

  2. Das Hinzufügen zusätzlicher Schritte in einem Prozess macht ihn möglicherweise schneller und nicht langsamer. Dies kann durch die Tatsache veranschaulicht werden, dass Sie a optimieren können, indem Sie SELECTes in zwei Schritte aufteilen, den ersten Wert in einer neu erstellten In-Memory-Tabelle speichern und dann die schwereren Abfragen für diese zweite Tabelle ausführen.

MySQL hat auch andere Indizes, aber ich denke, der B + Tree ist der am häufigsten verwendete und der Hash ist eine gute Sache zu wissen, aber Sie können die anderen in der MySQL-Dokumentation finden .

Ich empfehle Ihnen dringend, das Buch "High Performance MySQL" zu lesen. Die obige Antwort basierte definitiv auf dem Kapitel über Indizes.

klar
quelle
2
Haben folgende Abfragen im obigen Fall Vorteile? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Akshay Taru
1
Die erste Abfrage wird, die zweite Abfrage nicht. Verwenden Sie EXPLAIN: dev.mysql.com/doc/refman/5.5/en/explain.html Um die zweite Abfrage mit MySQL zu indizieren, müssen Sie den FULLTEXT INDEX verwenden: dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
Emilio Nicolás
5
Ich habe dich positiv bewertet, weil du bei 127 warst und die Antwort Nr. 1 bei 256. Ich konnte es nicht vermeiden, alles schön und sauber zu machen, binär.
Pbarney
Dies war eine neue Information für mich. "Die Reihenfolge, in der Sie diese Felder abfragen, ist sehr wichtig." Vielen Dank.
Khatri
1
@pbarney nach drei Jahren sind sie in der Nähe von 256 bzw. 512, das nenne ich eine binäre Erhöhung!
Nanocv
43

Grundsätzlich ist ein Index eine Karte aller Ihrer Schlüssel, die nacheinander sortiert ist. Wenn eine Liste in der richtigen Reihenfolge angezeigt wird, kann sie nicht jeden Schlüssel überprüfen, sondern Folgendes tun:

1: Zur Mitte der Liste gehen - ist höher oder niedriger als das, wonach ich suche?

2: Wenn höher, gehen Sie zur Mitte zwischen Mitte und unten, wenn niedriger, Mitte und oben

3: Ist höher oder niedriger? Springe wieder zum Mittelpunkt usw.

Mit dieser Logik können Sie ein Element in einer sortierten Liste in etwa 7 Schritten finden, anstatt jedes Element zu überprüfen.

Natürlich gibt es Komplexitäten, aber das gibt Ihnen die Grundidee.

Joshua
quelle
29
Dies wird als binäre Suche bezeichnet.
ddlshack
Danke, endlich eine Antwort, die erklärt, warum es schneller geht und nicht nur, wie die Datenbank mit Indizes funktioniert.
Gershon Herczeg
Die tatsächliche Anzahl der Schritte hängt stark von den Daten ab - Anzahl der eindeutigen Werte und Verteilung über Ihren Bereich. 7 ist das theoretische Maximum für 100 Werte. Vollständige Diskussion darüber, wie die Anzahl der Schritte hier berechnet wird stackoverflow.com/questions/10571170/…
Joshua
Der häufigste MySQL-Index ist ein B + -Baum, der ähnlich wie eine binäre Suche funktioniert, jedoch nicht ganz gleich ist. Die algorithmische Komplexität ist dieselbe, die Suche jedoch nicht. Siehe en.wikipedia.org/wiki/B-tree
Matt
4

Schauen Sie sich diesen Link an: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

Wie sie funktionieren, ist zu weit gefasst, um in einem SO-Beitrag behandelt zu werden.

Hier ist eine der besten Erklärungen für Indizes, die ich gesehen habe. Leider ist es für SQL Server und nicht für MySQL. Ich bin mir nicht sicher, wie ähnlich die beiden sind ...

Abe Miessler
quelle
2
Schöner Artikel. Ich kenne SQL Server nicht, aber die grundlegenden Funktionen funktionieren sehr ähnlich. (Metanote: Deaktivieren von CSS-Stilen im 2. verlinkten Artikel blendet den Inhalt ein)
Piskvor verließ das Gebäude
3

In diesen Videos finden Sie weitere Informationen zur Indizierung

Einfache Indizierung Sie können einen eindeutigen Index für eine Tabelle erstellen. Ein eindeutiger Index bedeutet, dass zwei Zeilen nicht denselben Indexwert haben können. Hier ist die Syntax zum Erstellen eines Index für eine Tabelle

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

Sie können eine oder mehrere Spalten verwenden, um einen Index zu erstellen. Zum Beispiel können wir einen Index für die tutorials_tblVerwendung von tutorial_author erstellen .

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

Sie können einen einfachen Index für eine Tabelle erstellen. Lassen Sie einfach das Schlüsselwort UNIQUE in der Abfrage weg, um einen einfachen Index zu erstellen. Der einfache Index ermöglicht doppelte Werte in einer Tabelle.

Wenn Sie die Werte in einer Spalte in absteigender Reihenfolge indizieren möchten, können Sie das reservierte Wort DESC nach dem Spaltennamen hinzufügen.

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)
shahirnana
quelle
1
Willkommen bei Stack Overflow! Ich habe festgestellt, dass alle Ihre Antworten auf Ihre eigenen Videos verweisen. Bitte beachten Sie, dass eine offene Eigenwerbung nicht zulässig ist .
SL Barth - Wiedereinsetzung Monica
Er möchte seine Videos bewerben. LOL
Ilyas Karim
1

Ich möchte meine 2 Cent hinzufügen. Ich bin weit davon entfernt, ein Datenbankexperte zu sein, aber ich habe kürzlich ein wenig über dieses Thema gelesen. genug für mich, um zu versuchen, einen ELI5 zu geben. Hier ist also die Erklärung eines Laien.


Ich verstehe es als solches, dass ein Index wie ein Mini-Spiegel Ihrer Tabelle ist, so ziemlich wie ein assoziatives Array. Wenn Sie es mit einem passenden Schlüssel füttern, können Sie einfach in einem "Befehl" zu dieser Zeile springen.

Wenn Sie diesen Index / dieses Array nicht hatten, muss der Abfrageinterpreter eine for-Schleife verwenden, um alle Zeilen zu durchsuchen und nach einer Übereinstimmung zu suchen (der vollständige Tabellenscan).

Ein Index hat den "Nachteil" eines zusätzlichen Speichers (für diesen Minispiegel), im Gegenzug für den "Vorteil", Inhalte schneller nachzuschlagen.

Beachten Sie, dass beim Erstellen von Primär-, Fremd- oder eindeutigen Schlüsseln (abhängig von Ihrer Datenbank-Engine) automatisch auch ein entsprechender Index erstellt wird. Das gleiche Prinzip ist im Grunde, warum und wie diese Schlüssel funktionieren.

WoodrowShigeru
quelle
1

Hinzufügen einer visuellen Darstellung zur Liste der Antworten. Geben Sie hier die Bildbeschreibung ein

MySQL verwendet eine zusätzliche Indirektionsebene: Sekundärindexdatensätze verweisen auf Primärindexdatensätze, und der Primärindex selbst enthält die Zeilenpositionen auf der Festplatte. Wenn sich ein Zeilenversatz ändert, muss nur der Primärindex aktualisiert werden.

Vorsichtsmaßnahme: Die Datenträgerdatenstruktur sieht im Diagramm flach aus, ist jedoch tatsächlich ein B + -Baum.

Quelle: Link

Anush
quelle
1

In MySQL InnoDB gibt es zwei Arten von Indizes.

  1. Primärschlüssel, der als Clustered-Index bezeichnet wird. Indexschlüsselwörter werden mit realen Datensatzdaten im B + Tree-Blattknoten gespeichert.

  2. Sekundärschlüssel, bei dem es sich nicht um einen Clustered-Index handelt. Diese Indizes speichern nur die Schlüsselwörter des Primärschlüssels zusammen mit ihren eigenen Indexschlüsselwörtern im B + Tree-Blattknoten. Wenn Sie also vom Sekundärindex aus suchen, werden zuerst die Schlüsselwörter des Primärschlüsselindex gefunden und der Primärschlüssel B + Tree gescannt, um die realen Datensätze zu finden. Dies verlangsamt den Sekundärindex im Vergleich zur Primärindexsuche. Wenn sich selectjedoch alle Spalten im Sekundärindex befinden, müssen Sie den Primärindex B + Tree nicht erneut nachschlagen. Dies wird als Deckungsindex bezeichnet.

sendon1982
quelle