MySQL-Indizes - Was sind die Best Practices?

208

Ich verwende seit einiger Zeit Indizes für meine MySQL-Datenbanken, habe sie jedoch nie richtig kennengelernt . Im Allgemeinen füge ich einen Index für alle Felder hinzu, die ich mithilfe einer WHEREKlausel suchen oder auswählen werde, aber manchmal scheint es nicht so schwarzweiß zu sein.

Was sind die Best Practices für MySQL-Indizes?

Beispielsituationen / Dilemmata:

  • Wenn eine Tabelle sechs Spalten enthält und alle durchsuchbar sind, sollte ich alle oder keine indizieren?

  • Was sind die negativen Performance-Auswirkungen der Indexierung?

  • Wenn ich eine VARCHAR 2500-Spalte habe, die in Teilen meiner Website durchsucht werden kann, sollte ich sie indizieren?

Haroldo
quelle
5
Sie sollten die Frage wahrscheinlich erneut markieren. Die Auswahl der Indizes ist ein wichtiger Bestandteil für die Optimierung jedes Datenbankmodells. Und aus meiner Sicht nichts mit PHP zu tun.
VGE

Antworten:

242

Sie sollten auf jeden Fall etwas Zeit damit verbringen, sich mit der Indizierung zu beschäftigen. Es wird viel darüber geschrieben, und es ist wichtig zu verstehen, was los ist.

Im Allgemeinen legt ein Index den Zeilen einer Tabelle eine Reihenfolge auf.

Stellen Sie sich der Einfachheit halber vor, eine Tabelle sei nur eine große CSV-Datei. Immer wenn eine Zeile eingefügt wird, wird sie am Ende eingefügt . Die "natürliche" Reihenfolge der Tabelle ist also nur die Reihenfolge, in der Zeilen eingefügt wurden.

Stellen Sie sich vor, Sie haben diese CSV-Datei in einer sehr rudimentären Tabellenkalkulationsanwendung geladen. In dieser Tabelle werden lediglich die Daten angezeigt und die Zeilen in fortlaufender Reihenfolge nummeriert.

Stellen Sie sich nun vor, Sie müssen alle Zeilen mit dem Wert "M" in der dritten Spalte finden. Je nachdem, was Ihnen zur Verfügung steht, haben Sie nur eine Option. Sie scannen die Tabelle und überprüfen den Wert der dritten Spalte für jede Zeile. Wenn Sie viele Zeilen haben, kann diese Methode (ein "Tabellenscan") lange dauern!

Stellen Sie sich nun vor, Sie haben zusätzlich zu dieser Tabelle einen Index. Dieser bestimmte Index ist der Werteindex in der dritten Spalte. Der Index listet alle Werte aus der dritten Spalte in einer aussagekräftigen Reihenfolge (z. B. alphabetisch) auf und enthält für jeden von ihnen eine Liste der Zeilennummern, in denen dieser Wert angezeigt wird.

Jetzt haben Sie eine gute Strategie, um alle Zeilen zu finden, in denen der Wert der dritten Spalte "M" ist. Zum Beispiel können Sie eine binäre Suche durchführen ! Während beim Tabellenscan N Zeilen gesucht werden müssen (wobei N die Anzahl der Zeilen ist), müssen Sie bei der binären Suche im schlimmsten Fall nur log-n Indexeinträge betrachten. Wow, das ist sicher viel einfacher!

Wenn Sie über diesen Index verfügen und der Tabelle Zeilen hinzufügen (am Ende, da unsere konzeptionelle Tabelle so funktioniert), müssen Sie den Index natürlich jedes Mal aktualisieren. Sie erledigen also etwas mehr Arbeit, während Sie neue Zeilen schreiben, aber Sie sparen eine Menge Zeit, wenn Sie nach etwas suchen.

Im Allgemeinen führt die Indizierung zu einem Kompromiss zwischen Lese- und Schreibeffizienz. Ohne Indizes können Einfügungen sehr schnell sein - das Datenbankmodul fügt der Tabelle nur eine Zeile hinzu. Beim Hinzufügen von Indizes muss die Engine jeden Index aktualisieren, während das Einfügen ausgeführt wird.

Auf der anderen Seite werden Lesevorgänge viel schneller.

Hoffentlich deckt das Ihre ersten beiden Fragen ab (wie andere beantwortet haben - Sie müssen das richtige Gleichgewicht finden).

Ihr drittes Szenario ist etwas komplizierter. Wenn Sie LIKE verwenden, helfen Indizierungs-Engines normalerweise bei Ihrer Lesegeschwindigkeit bis zum ersten "%". Mit anderen Worten, wenn Sie SELECTING WHERE-Spalte wie 'foo% bar%' auswählen, verwendet die Datenbank den Index, um alle Zeilen zu finden, in denen die Spalte mit "foo" beginnt, und muss dann dieses Zwischenzeilenset scannen, um die Teilmenge zu finden das enthält "bar". SELECT ... WHERE Spalte LIKE '% bar%' kann den Index nicht verwenden. Ich hoffe du kannst sehen warum.

Schließlich müssen Sie über Indizes für mehr als eine Spalte nachdenken. Das Konzept ist das gleiche und verhält sich ähnlich wie bei LIKE. Wenn Sie einen Index für (a, b, c) haben, verwendet die Engine den Index weiterhin so gut wie möglich von links nach rechts. Eine Suche in Spalte a könnte also den Index (a, b, c) verwenden, ebenso wie eine in (a, b). Die Engine müsste jedoch einen vollständigen Tabellenscan durchführen, wenn Sie suchen, WO b = 5 UND c = 1)

Hoffentlich hilft dies dabei, ein wenig Licht ins Dunkel zu bringen, aber ich muss wiederholen, dass Sie am besten ein paar Stunden damit verbringen, nach guten Artikeln zu suchen, die diese Dinge ausführlich erklären. Es ist auch eine gute Idee, die Dokumentation Ihres speziellen Datenbankservers zu lesen. Die Art und Weise, wie Indizes von Abfrageplanern implementiert und verwendet werden, kann sehr unterschiedlich sein.

timdev
quelle
10
Was ist mit den FULLTEXTIndizes? Können sie bei Bedingungen wie helfen LIKE '%bar%'?
Septagramm
2
@Septagram - FULLTEXTkann bei dieser Abfrage helfen , wenn bar es sich um ein "Wort" handelt. FULLTEXTbehandelt Wörter, nicht beliebige Teilzeichenfolgen (wie LIKEauch).
Rick James
@ Timdev explizit in welchem ​​Teil wurde die erste Frage beantwortet? Ich kann die zweite und dritte Frage erkennen, die im ersten und zweiten Teil (vor und nach Hoffentlich Ihre ersten beiden Fragen ) Ihrer wertvollen Antwort beantwortet wurden
Manuel Jordan
1
@ManuelJordan - Es gibt keine einfache Antwort auf die erste Frage. Dies hängt davon ab, wie Sie die Kompromisse im Kontext der erwarteten (oder noch besser beobachteten) Nutzung ausgleichen möchten.
Timdev
57

Schauen Sie sich Präsentationen wie More Mastering the Art of Indexing an .

Update 12/2012: Ich habe eine neue Präsentation von mir veröffentlicht: Wie man Indizes wirklich entwirft . Ich habe dies im Oktober 2012 auf der ZendCon in Santa Clara und im Dezember 2012 auf der Percona Live London vorgestellt.

Das Entwerfen der besten Indizes ist ein Prozess, der mit den Abfragen übereinstimmen muss, die Sie in Ihrer App ausführen.

Es ist schwierig, allgemeine Regeln zu empfehlen, welche Spalten am besten indiziert werden können oder ob Sie alle Spalten indizieren sollten, keine Spalten, welche Indizes mehrere Spalten umfassen sollen usw. Dies hängt von den Abfragen ab, die Sie ausführen müssen.

Ja, es gibt einen gewissen Overhead, sodass Sie keine unnötigen Indizes erstellen sollten. Sie sollten jedoch die Indizes erstellen, die den Abfragen zugute kommen, die Sie für eine schnelle Ausführung benötigen. Der Overhead eines Index wird in der Regel durch seinen Nutzen bei weitem aufgewogen.

Für eine Spalte mit dem Namen VARCHAR (2500) möchten Sie wahrscheinlich einen FULLTEXT-Index oder einen Präfixindex verwenden :

CREATE INDEX i ON SomeTable(longVarchar(100));

Beachten Sie, dass ein herkömmlicher Index nicht helfen kann, wenn Sie nach Wörtern suchen, die sich möglicherweise in der Mitte dieses langen Varchars befinden. Verwenden Sie dazu einen Volltextindex.

Bill Karwin
quelle
3
Ich danke dir sehr. slidehare.net/matsunobu/… war in der Tat sehr hilfreich.
Bishal Paudel
1
Hervorragend die Präsentation von slidehare.net/billkarwin/how-to-design-indexes-really
Manuel Jordan
1
Erstaunliche Präsentation (die von 2012), wirklich den ganzen Sinn der Indizes verstanden.
DarkteK
46

Ich werde einige der guten Ratschläge in anderen Antworten nicht wiederholen, aber hinzufügen:

Zusammengesetzte Indizes

Sie können zusammengesetzte Indizes erstellen - einen Index, der mehrere Spalten enthält. MySQL kann diese von links nach rechts verwenden . Also, wenn Sie haben:

Table A
Id
Name
Category
Age
Description

Wenn Sie einen zusammengesetzten Index haben, der Name / Kategorie / Alter in dieser Reihenfolge enthält, verwenden diese WHERE-Klauseln den Index:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

aber

WHERE Category='A' and Age > 18

würde diesen Index nicht verwenden, da alles von links nach rechts verwendet werden muss.

Erklären

Verwenden Sie Explain / Explain Extended, um zu verstehen, welche Indizes für MySQL verfügbar sind und welche tatsächlich ausgewählt werden. MySQL verwendet nur EINEN Schlüssel pro Abfrage .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Langsames Abfrageprotokoll

Aktivieren Sie das langsame Abfrageprotokoll, um festzustellen , welche Abfragen langsam ausgeführt werden.

Breite Spalten

Wenn Sie eine breite Spalte haben, in der der größte Teil der Unterscheidung in den ersten mehreren Zeichen erfolgt, können Sie nur die ersten N Zeichen in Ihrem Index verwenden. Beispiel: Wir haben eine ReferenceNumber-Spalte als varchar (255) definiert, aber in 97% der Fälle beträgt die Referenznummer 10 Zeichen oder weniger. Ich habe den Index so geändert, dass nur die ersten 10 Zeichen angezeigt werden, und die Leistung erheblich verbessert.

Eric J.
quelle
Ich habe eine Frage zum letzten Teil. Ich habe irgendwo gelesen, dass Sie beim Erstellen einer Spalte mit VARCHAR immer 255 festlegen sollten. Nun haben Sie gesagt, dass ein Index, der auf diesen Spaltentyp festgelegt ist, nur auf die ersten 10 Zeichen beschränkt sein kann. Wie genau kannst du das machen?
AlexioVay
20

Wenn eine Tabelle sechs Spalten hat und alle durchsuchbar sind, sollte ich alle oder keine indizieren

Suchen Sie feldweise oder verwenden einige Suchvorgänge mehrere Felder? Auf welchen Feldern wird am häufigsten gesucht? Was sind die Feldtypen? (Index funktioniert beispielsweise bei INTs besser als bei VARCHARs.) Haben Sie versucht, EXPLAIN für die ausgeführten Abfragen zu verwenden?

Was sind die negativen Auswirkungen der Indizierung auf die Leistung?

UPDATEs und INSERTs sind langsamer. Es gibt auch zusätzlichen Speicherplatzbedarf, aber das ist heutzutage normalerweise unwichtig.

Wenn ich eine VARCHAR 2500-Spalte habe, die in Teilen meiner Website durchsucht werden kann, sollte ich sie indizieren

Nein, es sei denn, es ist EINZIGARTIG (was bedeutet, dass es bereits indiziert ist) oder Sie suchen nur nach genauen Übereinstimmungen in diesem Feld (ohne die Volltextsuche von LIKE oder mySQL).

Im Allgemeinen füge ich einen Index für alle Felder hinzu, die ich mit einer WHERE-Klausel suchen oder auswählen werde

Normalerweise indiziere ich die Felder, die am häufigsten abgefragt werden, und dann INTs / BOOLEANs / ENUMs, anstatt Felder, die VARCHARS sind. Vergessen Sie nicht, dass Sie häufig einen Index für kombinierte Felder erstellen müssen, anstatt einen Index für ein einzelnes Feld. Verwenden Sie EXPLAIN und überprüfen Sie das langsame Protokoll.

Pete
quelle
11

Effizientes Laden von Daten : Indizes beschleunigen das Abrufen, verlangsamen jedoch das Einfügen und Löschen sowie das Aktualisieren von Werten in indizierten Spalten. Das heißt, Indizes verlangsamen die meisten Vorgänge, bei denen geschrieben wird. Dies liegt daran, dass für das Schreiben einer Zeile nicht nur die Datenzeile geschrieben werden muss, sondern auch Änderungen an den Indizes. Je mehr Indizes eine Tabelle hat, desto mehr Änderungen müssen vorgenommen werden und desto größer ist die durchschnittliche Leistungsverschlechterung. Die meisten Tabellen erhalten viele Lese- und Schreibvorgänge. Bei einer Tabelle mit einem hohen Prozentsatz an Schreibvorgängen können die Kosten für die Indexaktualisierung jedoch erheblich sein.

Indizes vermeiden : Wenn Sie keinen bestimmten Index benötigen, um die Leistung von Abfragen zu verbessern, erstellen Sie ihn nicht.

Speicherplatz : Ein Index belegt Speicherplatz, und mehrere Indizes belegen entsprechend mehr Speicherplatz. Dies kann dazu führen, dass Sie schneller eine Tabellengrößenbeschränkung erreichen, als wenn keine Indizes vorhanden sind. Vermeiden Sie nach Möglichkeit Indizes.

Takeaway: Nicht über Index

Srikar Doddi
quelle
5

Im Allgemeinen helfen Indizes dabei, die Datenbanksuche zu beschleunigen, da sie den zusätzlichen Speicherplatz benötigen und INSERT/ UPDATE/ DELETEAbfragen verlangsamen . Verwenden EXPLAINund lesen Sie die Ergebnisse, um herauszufinden, wann MySQL Ihre Indizes verwendet.

Wenn eine Tabelle sechs Spalten enthält und alle durchsuchbar sind, sollte ich alle oder keine indizieren?

Das Indizieren aller sechs Spalten ist nicht immer die beste Vorgehensweise.

(a) Verwenden Sie eine dieser Spalten, wenn Sie nach bestimmten Informationen suchen?

(b) Wie ist die Selektivität dieser Spalten (wie viele unterschiedliche Werte sind dort gespeichert, verglichen mit der Gesamtzahl der Datensätze in der Tabelle)?

MySQL verwendet einen kostenbasierten Optimierer, der versucht, beim Ausführen einer Abfrage den "billigsten" Pfad zu finden. Und Felder mit geringer Selektivität sind keine guten Kandidaten.

Was sind die negativen Auswirkungen der Indizierung auf die Leistung?

Bereits beantwortet: zusätzlicher Speicherplatz, geringere Leistung beim Einfügen - Aktualisieren - Löschen.

Wenn ich eine VARCHAR 2500-Spalte habe, die in Teilen meiner Website durchsucht werden kann, sollte ich sie indizieren?

Probieren Sie den FULLTEXT-Index aus .

Eine Axt
quelle
4

1/2) Indizes beschleunigen bestimmte Auswahlvorgänge, verlangsamen jedoch andere Vorgänge wie Einfügen, Aktualisieren und Löschen. Es kann eine gute Balance sein.

3) Verwenden Sie einen Volltextindex oder vielleicht eine Sphinx

Paul Creasey
quelle
Um dies zu verhindern slow down other operations like insert, update and deletes, können Sie START TRANSACTION; YOUR CODE HERE; COMMIT Folgendes verwenden, um slowing downdie anderen Vorgänge zu vermeiden , da nur eine der Einschränkungen einmal überprüft wird. CAVEAT: Wenn Sie REPLACE INTOund Ihre SQL_MODE<> STRICT_ALL_TABLESODER TRADITIONALDas Bulk Loadignoriert die ersetzen in und Einsatz von Duplikaten.
JayRizzo
Transaktionen werden nicht in allen MySQL-Engines unterstützt. AFAIK, Transaktionen verlangsamen DB-Operationen, auch wenn sie nur implizit verwendet werden. Was wir basierend auf der tatsächlichen Leistung entwerfen müssen, ist eine halbautomatische Methode zum Profilieren (Messen der Leistung) verschiedener Optimierungsoptionen, einschließlich Indizes und Transaktionen.
David Spector