Wie füge ich MySQL-Tabellen Indizes hinzu?


407

Ich habe eine sehr große MySQL-Tabelle mit ungefähr 150.000 Datenzeilen. Derzeit, wenn ich versuche zu laufen

SELECT * FROM table WHERE id = '1';

Der Code läuft einwandfrei, da das ID-Feld der Primärindex ist. Für eine aktuelle Entwicklung im Projekt muss ich die Datenbank jedoch nach einem anderen Feld durchsuchen. Zum Beispiel:

SELECT * FROM table WHERE product_id = '1';

Dieses Feld wurde zuvor nicht indiziert. Ich habe jedoch eine hinzugefügt, sodass mysql das Feld jetzt indiziert. Wenn ich jedoch versuche, die obige Abfrage auszuführen, wird sie sehr langsam ausgeführt. Eine EXPLAIN-Abfrage zeigt, dass es keinen Index für das Feld product_id gibt, wenn ich bereits einen hinzugefügt habe. Daher dauert die Abfrage zwischen 20 und 30 Minuten, um eine einzelne Zeile zurückzugeben.

Meine vollständigen EXPLAIN-Ergebnisse sind:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

Es kann hilfreich sein zu beachten, dass ich gerade einen Blick darauf geworfen habe und das ID-Feld als INT gespeichert ist, während das PRODUCT_ID-Feld als VARCHAR gespeichert ist. Könnte dies die Ursache des Problems sein?


1
Können Sie die vollständigen EXPLAINErgebnisse veröffentlichen? Sind Sie sicher, dass es keinen Index gibt? Oder ist der Index dort, aber MySQL entscheidet sich dafür, ihn nicht zu verwenden?
VoteyDisciple

169
Ein großer Tisch hätte 150.000.000 Datensätze. Eine sehr große Tabelle enthält 15.000.000.000 Datensätze. Eine Tabelle mit durchschnittlicher Größe hat 150.000. Zum späteren Nachschlagen.
Usumoio

4
Beachten Sie, dass MySql durch 'ODER' keine Indizes verwenden kann. Ich hatte eine Anfrage mit 3 OPs. Jeder bearbeitete einen Index und lief in 15 ms. Alle zusammen dauerten zwischen 25 Sekunden und Timeout. Also habe ich 3 Abfragen gemacht und UNION'ed sie zusammen, es dauerte auch 15ms auf 500.000 Zeilen.
Leif Neland

Betrachten Sie den Datentyp, den Sie speichern. Die Leistung kann sich je nach dem zu vergleichenden Datentyp ändern. Wie Sie bereits sagten, ist PRODUCT_ID ein VARCHAR-Datentyp. Versuchen Sie, ihn in einen INT zu ändern, und indizieren Sie die Spalte.
Gilbertdim

Antworten:


604
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

Nie vergleichen integerzu stringsin MySQL. Wenn idja int, entfernen Sie die Anführungszeichen.


Ich habe den Index bereits mit genau diesem SQL hinzugefügt, aber es scheint, dass er nicht auf die Daten "angewendet" wurde, und die EXPLAIN-Abfrage zeigt, dass es keinen Index für das Feld gibt.
Michael

1
Möchten Sie den Index mit einer SHOW CREATE TABLE überprüfen, oder haben Sie das bereits getan?
Wrikken

33
Verwenden Sie SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html , um zu überprüfen, ob die Indizes hinzugefügt wurden
Timo Huovinen

6
Heute hatte ich das genaue Problem, das @Michael beschreibt, und die Lösung bestand darin, "niemals eine Ganzzahl mit Zeichenfolgen in MySQL zu vergleichen". Vielen Dank.
user12345

@Wrikken Ich habe meinen Index hinzugefügt und Ihren Befehl SHOW INDEXES FROM YOURTABLE verwendet. Es wird angezeigt, aber ich glaube nicht, dass es verwendet wird, während ich meine Tabelle abfrage. Muss ich die Auswahlabfrage ändern, wenn ich einen Index verwende?
Ced

147
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

96
In MySQL, wenn Sie verwenden ALTER TABLE tbl ADD INDEX (col)statt ALTER TABLE tbl ADD INDEX col (col), dann unter Verwendung von ALTER TABLE tbl ADD INDEX (col)mehr als einmal wird das Hinzufügen Indizes genannt halten col_2, col_3... jedes Mal. Während mit ALTER TABLE tbl ADD INDEX col (col)2. Mal geben wird ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza

81

Mit dieser Syntax können Sie einen Index hinzufügen und die Art des Index (HASH oder BTREE) steuern.

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

Informationen zu Unterschieden zwischen BTREE- und HASH-Indizes finden Sie hier: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html


1
Hash wurde in btree konvertiert, wenn ich Show-Indizes verwende.
RN Kushwaha

1
Was ist die Standardeinstellung von Hash und BTree, wenn ich keine spezifiziere?
Bhavuk Mathur

2
@ RNKushwaha, weil InnoDB und MyIsam HASH, AFAIK nicht unterstützen, nur Speicher- und NDB-Speicher-Engines unterstützen es
Hieu Vo

60

Es ist erwähnenswert, dass mehrere Feldindizes Ihre Abfrageleistung drastisch verbessern können. Im obigen Beispiel nehmen wir an, dass ProductID das einzige zu suchende Feld ist. Wenn jedoch die Abfrage ProductID = 1 AND Category = 7 lautet, hilft ein mehrspaltiger Index. Dies wird mit folgendem erreicht:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

Außerdem sollte der Index mit der Reihenfolge der Abfragefelder übereinstimmen. In meinem erweiterten Beispiel sollte der Index (ProductID, Category) nicht umgekehrt sein.


1
Eine nette, explizite Benennung des Index ermöglicht eine einfache Umkehrung.
Sam Berry

Können Sie die Quelle von zitieren the index should match the order of the query fields?
Bishwas Mishra

58

Es können Indizes von zwei Typen hinzugefügt werden: Wenn Sie einen Primärschlüssel definieren, wird dieser von MySQL standardmäßig als Index verwendet.

Erläuterung

Primärschlüssel als Index

Angenommen, Sie haben eine tbl_studentTabelle und möchten student_idals Primärschlüssel:

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

Die obige Anweisung fügt einen Primärschlüssel hinzu. Dies bedeutet, dass indizierte Werte eindeutig sein müssen und nicht NULL sein dürfen.

Geben Sie den Indexnamen an

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

Die obige Anweisung erstellt einen normalen Index mit student_indexNamen.

Erstellen Sie einen eindeutigen Index

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

Hier student_unique_indexwird der Indexname student_id zugewiesen und ein Index erstellt, für den Werte eindeutig sein müssen (hier kann null akzeptiert werden).

Volltextoption

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

Die obige Anweisung erstellt den Volltextindexnamen mit student_fulltext_index obige , für den Sie MyISAM Mysql Engine benötigen.

Wie entferne ich Indizes?

DROP INDEX `student_index` ON `tbl_student`

Wie überprüfe ich verfügbare Indizes?

SHOW INDEX FROM `tbl_student`

17

Sie sagen, Sie haben einen Index, die Erklärung sagt etwas anderes. Wenn Sie dies jedoch wirklich tun, gehen Sie wie folgt vor:

Wenn Sie einen Index für die Spalte haben und MySQL beschließt, ihn nicht zu verwenden, kann dies daran liegen, dass:

  1. Es gibt einen anderen Index in der Abfrage, den MySQL für geeigneter hält, und er kann nur einen verwenden. Die Lösung ist normalerweise ein Index, der sich über mehrere Spalten erstreckt, wenn ihre normale Abrufmethode ein Wert von mehr als einer Spalte ist.
  2. MySQL entscheidet, dass es zu viele übereinstimmende Zeilen gibt, und denkt, dass ein Tabellenscan wahrscheinlich schneller ist. Wenn das nicht der Fall ist, ANALYZE TABLEhilft manchmal ein .
  3. Bei komplexeren Abfragen wird entschieden, es nicht auf der Grundlage eines äußerst intelligenten, durchdachten Voodoos im Abfrageplan zu verwenden, das aus irgendeinem Grund einfach nicht Ihren aktuellen Anforderungen entspricht.

Im Fall von (2) oder (3) könnten Sie MySQL dazu bringen, den Index nach Indexhinweis-Sytax zu verwenden . Wenn Sie dies jedoch tun, führen Sie einige Tests durch, um festzustellen, ob sich die Leistung tatsächlich verbessert, wenn Sie den Index so verwenden, wie Sie ihn andeuten .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.