Wenn die MySQL-Abfrageoptimierung erwähnt wird, sind Indizes eines der ersten Dinge, die behandelt werden. Heute werden wir versuchen herauszufinden, warum sie so wichtig sind.
Was sind Indizes?
Im Allgemeinen ist ein Index eine alphabetische Liste von Datensätzen mit Verweisen auf die Seiten, auf denen sie erwähnt werden. In MySQL ist ein Index eine Datenstruktur, die zum schnellen Auffinden von Zeilen verwendet wird. Indizes werden auch als Schlüssel bezeichnet, und diese Schlüssel sind entscheidend für eine gute Leistung. Je größer die Daten werden, desto wichtiger kann die Notwendigkeit der ordnungsgemäßen Verwendung von Indizes werden. Die Verwendung von Indizes ist eine der leistungsstärksten Methoden zur Verbesserung der Abfrageleistung - wenn Indizes richtig verwendet werden, kann die Abfrageleistung um das Zehn- oder sogar Hundertfache gesteigert werden.
Heute werden wir versuchen, die grundlegenden Vor- und Nachteile der Verwendung von Indizes in MySQL zu erklären. Denken Sie daran, dass MySQL-Indizes allein ein ganzes Buch verdienen, daher wird dieser Beitrag nicht absolut alles abdecken, aber er wird ein guter Ausgangspunkt sein. Für diejenigen, die daran interessiert sind, wie Indizes auf einer tieferen Ebene funktionieren, sollte die Lektüre des Buches Relational Database Index Design and the Optimizers von Tapio Lahdenmäki und Michael Leach mehr Einblick geben.
Die Vorteile der Verwendung von Indizes
Es gibt ein paar Hauptvorteile der Verwendung von Indizes in MySQL und diese sind wie folgt:
- Indizes ermöglichen es, schnell Zeilen zu finden, die mit einer WHERE-Klausel übereinstimmen;
- Indizes können Abfragen dabei helfen, das Durchsuchen bestimmter Zeilen zu vermeiden, wodurch die Datenmenge reduziert wird, die der Server untersuchen muss. Wenn es eine Auswahl zwischen mehreren Indizes gibt, verwendet MySQL normalerweise den selektivsten Index, also einen solchen Index, der die kleinste Anzahl an Zeilen findet;
- Indizes können verwendet werden, um Zeilen aus anderen Tabellen in JOIN-Operationen abzurufen;
- Indizes können verwendet werden, um den Mindest- oder Höchstwert einer bestimmten Spalte zu finden, die einen Index verwendet;
- Indizes können verwendet werden, um eine Tabelle zu sortieren oder zu gruppieren, wenn die Operationen auf einem ganz linken Präfix eines Index ausgeführt werden – ähnlich könnte auch ein ganz linkes Präfix eines mehrspaltigen Index vom Abfrageoptimierer verwendet werden Zeilen nachschlagen;
- Indizes können auch verwendet werden, um Festplatten-I/O zu sparen – wenn ein abdeckender Index verwendet wird, kann eine Abfrage Werte direkt aus der Indexstruktur zurückgeben und Festplatten-I/O sparen.
In ähnlicher Weise gibt es mehrere Arten von Indizes:
- INDEX ist ein Indextyp, bei dem Werte nicht eindeutig sein müssen. Dieser Indextyp akzeptiert NULL-Werte;
- UNIQUE INDEX wird häufig verwendet, um doppelte Zeilen aus einer Tabelle zu entfernen – diese Art von Index ermöglicht es Entwicklern, die Eindeutigkeit von Zeilenwerten zu erzwingen;
- FULLTEXT INDEX ist ein Index, der auf Felder angewendet wird, die Volltextsuchfunktionen verwenden. Diese Art von Index findet Schlüsselwörter im Text, anstatt Werte direkt mit den Werten im Index zu vergleichen;
- DESCENDING INDEX ist ein Index, der Zeilen in absteigender Reihenfolge speichert – der Abfrageoptimierer wählt diesen Indextyp, wenn eine absteigende Reihenfolge von der Abfrage angefordert wird. Dieser Indextyp wurde in MySQL 8.0 eingeführt;
- PRIMARY KEY ist auch ein Index. Kurz gesagt, der PRIMARY KEY ist eine Spalte oder eine Gruppe von Spalten, die jede Zeile in einer Tabelle identifiziert – häufig zusammen mit Feldern verwendet, die ein AUTO_INCREMENT-Attribut haben. Dieser Indextyp akzeptiert keine NULL-Werte und einmal festgelegte Werte im PRIMARY KEY können nicht mehr geändert werden.
Jetzt werden wir versuchen, sowohl die Vor- als auch die Nachteile der Verwendung von Indizes in MySQL durchzugehen. Wir beginnen mit dem wahrscheinlich am häufigsten diskutierten Vorteil – der Beschleunigung von Abfragen, die auf eine WHERE-Klausel passen.
Abfragen beschleunigen, die mit einer WHERE-Klausel übereinstimmen
Indizes werden häufig verwendet, um Suchanfragen zu beschleunigen, die mit einer WHERE-Klausel übereinstimmen. Der Grund, warum ein Index solche Suchoperationen beschleunigt, ist ziemlich einfach:Abfragen, die einen Index verwenden, vermeiden einen vollständigen Tabellenscan.
Um Abfragen zu beschleunigen, die mit einer WHERE-Klausel übereinstimmen, können Sie die EXPLAIN-Anweisung in MySQL verwenden. Die Anweisung EXPLAIN SELECT sollte Ihnen einen Einblick geben, wie der MySQL-Abfrageoptimierer die Abfrage ausführt - er kann Ihnen auch zeigen, ob die betreffende Abfrage einen Index verwendet oder nicht und welchen Index sie verwendet. Sehen Sie sich die folgende Abfrageerklärung an:
mysql> EXPLAIN SELECT * FROM demo_table WHERE field_1 = “Demo” \G;
*************************** 1. row ***************************
<...>
possible_keys: NULL
key: NULL
key_len: NULL
<...>
Die obige Abfrage verwendet keinen Index. Wenn wir jedoch einen Index zu „field_1“ hinzufügen, wird der Index erfolgreich verwendet:
mysql> EXPLAIN SELECT * FROM demo_table WHERE field_1 = “Demo” \G;
*************************** 1. row ***************************
<...>
possible_keys: field_1
key: field_1
key_len: 43
<...>
Die Spalte possible_keys beschreibt die möglichen Indizes, die MySQL wählen kann, die Spalte key beschreibt den tatsächlich gewählten Index und die Spalte key_len beschreibt die Länge des gewählten Schlüssels.
In diesem Fall würde MySQL eine Suche nach den Werten im Index durchführen und alle Zeilen zurückgeben, die den angegebenen Wert enthalten - als Ergebnis wäre die Abfrage schneller. Obwohl Indizes dazu beitragen, bestimmte Abfragen schneller zu machen, gibt es ein paar Dinge, die Sie beachten müssen, wenn Sie möchten, dass Ihre Indizes Ihre Abfragen unterstützen:
- Isolieren Sie Ihre Spalten – MySQL kann keine Indizes verwenden, wenn die Spalten, für die die Indizes verwendet werden, nicht isoliert sind. Beispielsweise würde eine Abfrage wie diese keinen Index verwenden:
SELECT field_1 FROM demo_table WHERE field_1 + 5 = 10;
Um dies zu lösen, lassen Sie die Spalte nach der WHERE-Klausel in Ruhe - vereinfachen Sie Ihre Abfrage so weit wie möglich und isolieren Sie die Spalten;
- Vermeiden Sie die Verwendung von LIKE-Abfragen mit einem vorangestellten Platzhalter – in diesem Fall verwendet MySQL keinen Index, da der vorangestellte Platzhalter bedeutet, dass vor dem Text alles stehen kann. Wenn Sie LIKE-Abfragen mit Platzhaltern verwenden müssen und möchten, dass die Abfragen Indizes verwenden, stellen Sie sicher, dass sich der Platzhalter am Ende der Suchanweisung befindet.
Natürlich kann das Beschleunigen von Abfragen, die mit einer WHERE-Klausel übereinstimmen, auch auf andere Weise erfolgen (z. B. Partitionieren), aber der Einfachheit halber gehen wir in diesem Beitrag nicht weiter darauf ein.
Was uns jedoch interessieren könnte, sind verschiedene Arten von Indextypen, also werden wir uns jetzt damit befassen.
Doppelte Werte in einer Spalte beseitigen - EINZIGARTIGE Indizes
Der Zweck eines UNIQUE-Index in MySQL besteht darin, die Eindeutigkeit der Werte in einer Spalte zu erzwingen. Um einen UNIQUE-Index zu verwenden, führen Sie eine CREATE UNIQUE INDEX-Abfrage aus:
CREATE UNIQUE INDEX demo_index ON demo_table(demo_column);
You can also create a unique index when you create a table:
CREATE TABLE demo_table (
`demo_column` VARCHAR(100) NOT NULL,
UNIQUE KEY(demo_column)
);
Mehr braucht es nicht, um einer Tabelle einen eindeutigen Index hinzuzufügen. Wenn Sie nun versuchen, der Tabelle einen doppelten Wert hinzuzufügen, wird MySQL mit dem folgenden Fehler zurückkommen:
#1062 - Duplicate entry ‘Demo’ for key ‘demo_column’
VOLLTEXT-Indizes
Ein FULLTEXT-Index ist ein solcher Index, der auf die Spalten angewendet wird, die Volltextsuchfunktionen verwenden. Diese Art von Index verfügt über viele einzigartige Funktionen, darunter Stoppwörter und Suchmodi.
Die InnoDB-Stoppwortliste hat 36 Wörter, während die MyISAM-Stoppwortliste 143 Wörter hat. In InnoDB werden die Stoppwörter von der Tabelle abgeleitet, die in der Variablen innodb_ft_user_stopword_table gesetzt ist, andernfalls, wenn diese Variable nicht gesetzt ist, werden sie abgeleitet aus der Variable innodb_ft_server_stopword_table. Wenn keine dieser beiden Variablen gesetzt ist, verwendet InnoDB die eingebaute Liste. Um die standardmäßige InnoDB-Stoppwortliste anzuzeigen, fragen Sie die Tabelle INNODB_FT_DEFAULT_STOPWORD ab.
In MyISAM werden die Stoppwörter aus der Datei storage/myisam/ft_static.c abgeleitet. Die Variable ft_stopword_file ermöglicht das Ändern der Standard-Stoppwortliste. Stoppwörter werden deaktiviert, wenn diese Variable auf einen leeren String gesetzt wird, aber denken Sie daran, dass, wenn diese Variable eine Datei definiert, die definierte Datei nicht nach Kommentaren durchsucht wird – MyISAM behandelt alle in der Datei gefundenen Wörter als Stoppwörter.
Die FULLTEXT-Indizes sind auch berühmt für ihre einzigartigen Suchmodi:
- Wenn eine VOLLTEXT-Suchanfrage ohne Modifikatoren ausgeführt wird, wird ein natürlicher Sprachmodus aktiviert. Der natürliche Sprachmodus kann auch mit dem Modifikator IN NATURAL LANGUAGE MODE aktiviert werden;
- Der Modifikator WITH QUERY EXPANSION aktiviert einen Suchmodus mit Abfrageerweiterung. Ein solcher Suchmodus funktioniert, indem die Suche zweimal durchgeführt wird, und wenn die Suche zum zweiten Mal ausgeführt wird, würde die Ergebnismenge einige der relevantesten Dokumente aus der ersten Suche enthalten. Im Allgemeinen ist dieser Modifikator nützlich, wenn der Benutzer über ein gewisses implizites Wissen verfügt (z. B. könnte der Benutzer nach „Datenbank“ suchen und hoffen, „InnoDB“ und „MyISAM“ in der Ergebnismenge zu sehen);
- Der Modifikator IN BOOLEAN MODE ermöglicht die Suche mit booleschen Operatoren. Beispielsweise würden die Operatoren +, - oder * jeweils unterschiedliche Aufgaben erfüllen - der Operator + würde definieren, dass der Wert in einer Zeile vorhanden sein muss, der Operator - würde definieren, dass der Wert nicht vorhanden sein darf, und der Operator * würde als a fungieren Platzhalter.
Eine Abfrage, die einen FULLTEXT-Index verwendet, sieht folgendermaßen aus:
SELECT * FROM demo_table WHERE MATCH(demo_field) AGAINST(‘value’ IN NATURAL LANGUAGE MODE);
Denken Sie daran, dass FULLTEXT-Indizes im Allgemeinen für MATCH()-AGAINST()-Operationen nützlich sind – nicht für WHERE-Operationen, was bedeutet, dass, wenn eine WHERE-Klausel verwendet würde, die Nützlichkeit der Verwendung unterschiedlicher Indextypen würde dadurch nicht eliminiert.
Es ist auch erwähnenswert, dass FULLTEXT-Indizes eine Mindestlänge von Zeichen haben. In InnoDB kann eine FULLTEXT-Suche nur durchgeführt werden, wenn die Suchanfrage aus mindestens drei Zeichen besteht - diese Grenze wird in der MyISAM-Speicher-Engine auf vier Zeichen erhöht.
INDESCENDING-Indizes
Ein DESCENDING-Index ist ein solcher Index, bei dem InnoDB die Einträge in absteigender Reihenfolge speichert - der Abfrageoptimierer verwendet einen solchen Index, wenn eine absteigende Reihenfolge von der Abfrage angefordert wird. Ein solcher Index kann einer Spalte hinzugefügt werden, indem eine Abfrage wie unten ausgeführt wird:
CREATE INDEX descending_index ON demo_table(column_name DESC);
Ein aufsteigender Index kann auch zu einer Spalte hinzugefügt werden - ersetzen Sie einfach DESC durch ASC.
PRIMÄRSCHLÜSSEL
EIN PRIMARY KEY dient als eindeutiger Bezeichner für jede Zeile in einer Tabelle. Eine Spalte mit einem PRIMARY KEY muss eindeutige Werte enthalten – es dürfen auch keine NULL-Werte verwendet werden. Wenn einer Spalte mit PRIMARY KEY ein doppelter Wert hinzugefügt wird, antwortet MySQL mit einem Fehler #1062:
#1062 - Duplicate entry ‘Demo’ for key ‘PRIMARY’
Wenn der Spalte ein NULL-Wert hinzugefügt wird, antwortet MySQL mit einem Fehler #1048:
#1048 - Column ‘id’ cannot be null
Primäre Indizes werden manchmal auch Cluster-Indizes genannt (wir besprechen sie später).
Sie können auch Indizes für mehrere Spalten gleichzeitig erstellen - solche Indizes werden Mehrspalten-Indizes genannt.
Mehrspaltige Indizes
Indizes für mehrere Spalten werden oft missverstanden - manchmal indizieren Entwickler und DBAs alle Spalten separat oder in der falschen Reihenfolge. Um Abfragen, die mehrspaltige Indizes verwenden, so effektiv wie möglich zu gestalten, denken Sie daran, dass die Reihenfolge der Spalten in Indizes, die mehr als eine Spalte verwenden, eine der häufigsten Ursachen für Verwirrung in diesem Bereich ist – da es kein „Hier oder die Autobahn“ gibt ” Lösungen für die Indexreihenfolge müssen Sie daran denken, dass die richtige Reihenfolge mehrspaltiger Indizes von den Abfragen abhängt, die den Index verwenden. Obwohl dies ziemlich offensichtlich erscheinen mag, denken Sie daran, dass die Spaltenreihenfolge beim Umgang mit mehrspaltigen Indizes von entscheidender Bedeutung ist. Wählen Sie die Spaltenreihenfolge so aus, dass sie für die Abfragen, die am häufigsten ausgeführt werden, so selektiv wie möglich ist.
Um die Selektivität für bestimmte Spalten zu messen, erhalten Sie das Verhältnis der Anzahl unterschiedlicher indizierter Werte zur Gesamtzahl der Zeilen in der Tabelle - die Spalte mit der höheren Selektivität sollte die erste sein .
Manchmal müssen Sie auch sehr lange Zeichenspalten indizieren, und in diesem Fall können Sie oft Zeit und Ressourcen sparen, indem Sie die ersten paar Zeichen - ein Präfix - anstelle des gesamten Werts indizieren.
Präfix-Indizes
Präfixindizes können nützlich sein, wenn die Spalten sehr lange Zeichenfolgenwerte enthalten, was bedeuten würde, dass das Hinzufügen eines Indexes für die gesamte Spalte viel Speicherplatz beanspruchen würde. MySQL hilft bei der Lösung dieses Problems, indem es Ihnen erlaubt, nur ein Präfix des Werts zu indizieren, wodurch wiederum die Indexgröße kleiner wird. Schau mal:
CREATE TABLE `demo_table` (
`demo_column` VARCHAR(100) NOT NULL,
INDEX(demo_column(10))
);
Die obige Abfrage würde einen Präfixindex für die Demospalte erstellen, der nur die ersten 10 Zeichen des Werts indiziert. Sie können einer bestehenden Tabelle auch einen Präfixindex hinzufügen:
CREATE INDEX index_name ON table_name(column_name(length));
Wenn Sie also beispielsweise die ersten 5 Zeichen einer demo_column in einer demo_table indizieren möchten, können Sie die folgende Abfrage ausführen:
CREATE INDEX demo_index ON demo_table(demo_column(5));
Sie sollten ein Präfix wählen, das lang genug ist, um Selektivität zu bieten, aber auch kurz genug, um Platz zu schaffen. Dies ist jedoch möglicherweise leichter gesagt als getan - Sie müssen experimentieren und die Lösung finden, die für Sie funktioniert.
Indizes abdecken
Ein abdeckender Index „deckt“ alle erforderlichen Felder ab, um eine Abfrage auszuführen. Mit anderen Worten, wenn alle Felder in einer Abfrage von einem Index abgedeckt werden, wird ein abdeckender Index verwendet. Zum Beispiel für eine Abfrage wie diese:
SELECT id, title FROM demo_table WHERE id = 1;
Ein abdeckender Index könnte so aussehen:
INDEX index_name(id, title);
Wenn Sie sicherstellen möchten, dass eine Abfrage einen abdeckenden Index verwendet, setzen Sie eine EXPLAIN-Anweisung darauf ab und werfen Sie dann einen Blick auf die Extra-Spalte. Wenn Ihre Tabelle beispielsweise einen mehrspaltigen Index für id und title hat und eine Abfrage ausgeführt wird, die nur auf diese beiden Spalten zugreift, verwendet MySQL den Index:
mysql> EXPLAIN SELECT id, title FROM demo_table \G;
*************************** 1. row ***************************
<...>
type: index
key: index_name
key_len: 5
rows: 1000
Extra: Using index
<...>
Denken Sie daran, dass ein abdeckender Index die Werte aus den Spalten speichern muss, die er abdeckt. Das bedeutet, dass MySQL nur B-Tree-Indizes verwenden kann, um Abfragen abzudecken, da andere Arten von Indizes diese Werte nicht speichern.
Clustered, Sekundärindizes und Indexkardinalität
Wenn es um Indizes geht, werden Sie vielleicht auch die Begriffe Clustered, Secondary Indexes und Index Cardinality hören. Einfach ausgedrückt sind Clustered-Indizes ein Ansatz zur Datenspeicherung, und alle Indizes außer Clustered-Indizes sind Sekundärindizes. Die Indexkardinalität hingegen ist die Anzahl der eindeutigen Werte in einem Index.
Ein Clustered-Index beschleunigt Abfragen, da nahe Werte auch nahe beieinander auf der Festplatte gespeichert werden, aber das ist auch der Grund, warum Sie nur einen Clustered-Index in einer Tabelle haben können.
Ein Sekundärindex ist jeder Index, der nicht der Primärindex ist. Ein solcher Index kann Duplikate haben.
Die Nachteile der Verwendung von Indizes
Die Verwendung von Indizes hat sicherlich Vorteile, aber wir dürfen nicht vergessen, dass Indizes auch eine der Hauptursachen für Probleme in MySQL sein können. Einige der Nachteile der Verwendung von Indizes sind die folgenden:
- Indizes können die Leistung bestimmter Abfragen verschlechtern – obwohl Indizes dazu neigen, die Leistung von SELECT-Abfragen zu beschleunigen, verlangsamen sie die Leistung von INSERT-, UPDATE- und DELETE-Abfragen, weil, wenn die Daten aktualisiert werden, die index muss ebenfalls zusammen mit ihm aktualisiert werden:jede Operation, die eine Manipulation der Indizes beinhaltet, wird langsamer als gewöhnlich sein;
- Indizes verbrauchen Speicherplatz – ein Index belegt seinen eigenen Speicherplatz, sodass indizierte Daten auch mehr Speicherplatz verbrauchen;
- Redundante und doppelte Indizes können ein Problem darstellen - MySQL erlaubt Ihnen, doppelte Indizes für eine Spalte zu erstellen, und es „schützt“ Sie nicht davor, einen solchen Fehler zu machen. Sehen Sie sich dieses Beispiel an:
CREATE TABLE `demo_table` ( `id` INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, `column_2` VARCHAR(10) NOT NULL, `column_3` VARCHAR(10) NOT NULL, INDEX(id), UNIQUE(id) );
Ein unerfahrener Benutzer könnte denken, dass diese Abfrage die ID-Spalte automatisch erhöht, dann einen Index zu der Spalte hinzufügt und dafür sorgt, dass die Spalte keine doppelten Werte akzeptiert. Dies ist jedoch nicht das, was hier passiert. In diesem Fall enthält dieselbe Spalte drei Indizes:einen gewöhnlichen INDEX, und da MySQL sowohl PRIMARY KEY- als auch UNIQUE-Einschränkungen mit Indizes implementiert, fügt das zwei weitere Indizes zu derselben Spalte hinzu!
Fazit
Abschließend haben Indizes in MySQL ihren eigenen Platz - Indizes können in einer Vielzahl von Szenarien verwendet werden, aber jedes dieser Nutzungsszenarien hat seine eigenen Nachteile, die berücksichtigt werden müssen, um das Beste daraus zu machen Indizes, die verwendet werden.
Um Indizes gut zu verwenden, profilieren Sie Ihre Abfragen, sehen Sie sich an, welche Optionen Sie in Bezug auf Indizes haben, kennen Sie deren Vor- und Nachteile, entscheiden Sie, welche Indizes Sie basierend auf Ihren Anforderungen benötigen, und stellen Sie nach der Indizierung der Spalten sicher, dass Ihre Indizes vorhanden sind tatsächlich von MySQL verwendet. Wenn Sie Ihr Schema richtig indiziert haben, sollte sich die Leistung Ihrer Abfragen verbessern, aber wenn Sie mit der Antwortzeit nicht zufrieden sind, prüfen Sie, ob ein besserer Index erstellt werden kann, um ihn zu verbessern.