Comment ajouter des index aux tables MySQL?

407

J'ai une très grande table MySQL avec environ 150 000 lignes de données. Actuellement, quand j'essaie de courir

SELECT * FROM table WHERE id = '1';

le code fonctionne correctement car le champ ID est l'index principal. Cependant, pour un développement récent dans le projet, je dois rechercher la base de données par un autre champ. Par exemple:

SELECT * FROM table WHERE product_id = '1';

Ce champ n'était pas indexé auparavant; cependant, j'en ai ajouté un, donc mysql indexe maintenant le champ, mais lorsque j'essaie d'exécuter la requête ci-dessus, il s'exécute très lentement. Une requête EXPLAIN révèle qu'il n'y a pas d'index pour le champ product_id lorsque j'en ai déjà ajouté un, et par conséquent la requête prend de 20 à 30 minutes pour renvoyer une seule ligne.

Mes résultats EXPLAIN complets sont:

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

Il peut être utile de noter que je viens de jeter un coup d'œil et que le champ ID est stocké en INT alors que le champ PRODUCT_ID est stocké en VARCHAR. Serait-ce la source du problème?

Michael
la source
1
Pouvez-vous publier les EXPLAINrésultats complets ? Êtes-vous certain que c'est qu'il n'y a pas d' index? Ou est-ce que l'index est là, mais MySQL a choisi de ne pas l'utiliser?
VoteyDisciple
169
Une grande table aurait 150 000 000 d'enregistrements. Une très grande table contient 15 000 000 000 d'enregistrements. Une table de taille moyenne en compte 150 000. Pour référence future.
usumoio
4
Sachez que «OU» peut empêcher MySql d'utiliser des index. J'ai eu une requête avec 3 OR. Chacun a machiné un index et a fonctionné en 15 ms, tous ensemble ont pris entre 25 secondes et le délai d'attente. J'ai donc fait 3 requêtes et les ai réunies ensemble, cela a également pris 15 ms sur 500 000 lignes.
Leif Neland
Tenez compte du type de données que vous stockez. Les performances peuvent changer en fonction du type de données que vous comparez. Comme vous l'avez dit, PRODUCT_ID est un type de données VARCHAR, essayez de le changer en INT et indexez la colonne.
gilbertdim

Réponses:

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

Ne jamais comparer integerà stringsMySQL. Si idc'est le cas int, supprimez les guillemets.

zerkms
la source
J'ai déjà ajouté l'index en utilisant ce SQL exact, mais il semble qu'il n'ait pas été "appliqué" aux données et la requête EXPLAIN montre qu'il n'y a pas d'index pour le champ.
Michael
1
Attention à vérifier l'index avec un SHOW CREATE TABLE, ou l'avez-vous déjà fait?
Wrikken
33
Utilisez SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html pour vérifier si les index ont été ajoutés
Timo Huovinen
6
Aujourd'hui, j'ai eu le problème exact décrit par @Michael, et la solution était de "ne jamais comparer l'entier aux chaînes dans mysql." Je vous remercie.
user12345
@Wrikken J'ai ajouté mon index et utilisé votre commande SHOW INDEXES FROM YOURTABLE. Il apparaît mais je ne pense pas qu'il soit utilisé pendant que j'interroge ma table. Dois-je modifier la requête de sélection lors de l'utilisation d'un index?
Ced
148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
pabloferraz
la source
97
En MySQL, si vous utilisez au ALTER TABLE tbl ADD INDEX (col)lieu de ALTER TABLE tbl ADD INDEX col (col), puis en utilisant ALTER TABLE tbl ADD INDEX (col)plus d'une fois gardera l' ajout d' indices nommés col_2, col_3... à chaque fois. Alors qu'en utilisant la ALTER TABLE tbl ADD INDEX col (col)2e fois, ça donnera ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza
82

Vous pouvez utiliser cette syntaxe pour ajouter un index et contrôler le type d'index (HASH ou BTREE).

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;

Vous pouvez en savoir plus sur les différences entre les index BTREE et HASH ici: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html

Hieu Vo
la source
1
Hash converti en btree quand je vois utiliser des index show.
RN Kushwaha
1
Quelle sera la valeur par défaut de Hash et BTree, si je n'en spécifie pas?
Bhavuk Mathur
2
@RNKushwaha car InnoDB et MyIsam ne prennent pas en charge HASH, AFAIK, seuls les moteurs de stockage Memory et NDB le prennent en charge
Hieu Vo
60

Il convient de noter que plusieurs index de champs peuvent considérablement améliorer les performances de votre requête. Donc, dans l'exemple ci-dessus, nous supposons que ProductID est le seul champ à rechercher, mais si la requête disait ProductID = 1 AND Category = 7, un index à plusieurs colonnes aide. Ceci est réalisé avec les éléments suivants:

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

En outre, l'index doit correspondre à l'ordre des champs de requête. Dans mon exemple étendu, l'index doit être (ProductID, Category) et non l'inverse.

Antony
la source
1
Nice, nommer explicitement l'index permet une inversion facile.
Sam Berry
Pouvez-vous citer la source de the index should match the order of the query fields?
Bishwas Mishra
58

Des index de deux types peuvent être ajoutés: lorsque vous définissez une clé primaire, MySQL la prend comme index par défaut.

Explication

Clé primaire comme index

Considérez que vous avez une tbl_studenttable et que vous voulez student_idcomme clé primaire:

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

L'instruction ci-dessus ajoute une clé primaire, ce qui signifie que les valeurs indexées doivent être uniques et ne peuvent pas être NULL.

Spécifiez le nom de l'index

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

L'instruction ci-dessus créera un index ordinaire avec student_index nom.

Créer un index unique

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

Ici, student_unique_index est le nom d'index attribué à student_id et crée un index dont les valeurs doivent être uniques (ici, null peut être accepté).

Option de texte intégral

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

L'instruction ci-dessus créera le nom d'index Fulltext avec student_fulltext_index lequel vous avez besoin de MyISAM Mysql Engine.

Comment supprimer des index?

DROP INDEX `student_index` ON `tbl_student`

Comment vérifier les index disponibles?

SHOW INDEX FROM `tbl_student`
Jazzzzzz
la source
17

Vous dites que vous avez un index, l'expliquer dit le contraire. Cependant, si vous le faites vraiment, voici comment continuer:

Si vous avez un index sur la colonne et que MySQL décide de ne pas l'utiliser, cela peut être dû à:

  1. Il y a un autre index dans la requête que MySQL juge plus approprié à utiliser, et il ne peut en utiliser qu'un seul. La solution est généralement un index couvrant plusieurs colonnes si leur méthode normale de récupération est en valeur de plus d'une colonne.
  2. MySQL décide qu'il y a trop de lignes correspondantes et pense qu'un scan de table est probablement plus rapide. Si ce n'est pas le cas, parfois unANALYZE TABLE aide.
  3. Dans les requêtes plus complexes, il décide de ne pas l'utiliser sur la base d'un vaudou réfléchi extrêmement intelligent dans le plan de requête qui, pour une raison quelconque, ne correspond tout simplement pas à vos besoins actuels.

Dans le cas de (2) ou (3), vous pouvez inciter MySQL à utiliser la syntaxe d' index par index , mais si vous le faites, assurez-vous d'exécuter des tests pour déterminer si cela améliore réellement les performances pour utiliser l'index lorsque vous l'indiquez. .

Wrikken
la source