Index MySQL - quelles sont les meilleures pratiques?


208

J'utilise des index sur mes bases de données MySQL depuis un certain temps maintenant mais je ne les ai jamais correctement appris . En général, je mets un index sur tous les champs que je vais rechercher ou sélectionner en utilisant une WHEREclause, mais parfois cela ne semble pas si noir et blanc.

Quelles sont les meilleures pratiques pour les index MySQL?

Exemples de situations / dilemmes:

  • Si une table comporte six colonnes et qu'elles sont toutes consultables, dois-je les indexer toutes ou aucune d'entre elles?

  • Quels sont les impacts négatifs sur les performances de l'indexation?

  • Si j'ai une colonne VARCHAR 2500 qui peut être recherchée à partir de parties de mon site, dois-je l'indexer?


5
Vous devriez probablement reformuler la question. Le choix des index est une partie importante pour l'optimisation de tout modèle de base de données. Et à mon point de vue sans rapport avec php.
VGE


Réponses:


242

Vous devriez certainement passer du temps à lire sur l'indexation, il y a beaucoup d'écrit à ce sujet et il est important de comprendre ce qui se passe.

D'une manière générale, un index impose un ordre sur les lignes d'une table.

Par souci de simplicité, imaginez qu'une table n'est qu'un gros fichier CSV. Chaque fois qu'une ligne est insérée, elle est insérée à la fin . Ainsi, l'ordre "naturel" de la table est simplement l'ordre dans lequel les lignes ont été insérées.

Imaginez que vous avez ce fichier CSV chargé dans une application de feuille de calcul très rudimentaire. Cette feuille de calcul n'affiche que les données et numérote les lignes dans un ordre séquentiel.

Imaginez maintenant que vous devez trouver toutes les lignes qui ont une valeur "M" dans la troisième colonne. Compte tenu de ce dont vous disposez, vous n'avez qu'une seule option. Vous scannez le tableau en vérifiant la valeur de la troisième colonne pour chaque ligne. Si vous avez beaucoup de lignes, cette méthode (un "scan de table") peut prendre beaucoup de temps!

Imaginez maintenant qu'en plus de ce tableau, vous avez un index. Cet index particulier est l'indice des valeurs dans la troisième colonne. L'index répertorie toutes les valeurs de la troisième colonne, dans un ordre significatif (par exemple, par ordre alphabétique) et pour chacune d'elles, fournit une liste des numéros de ligne où cette valeur apparaît.

Vous avez maintenant une bonne stratégie pour trouver toutes les lignes où la valeur de la troisième colonne est "M". Par exemple, vous pouvez effectuer une recherche binaire ! Alors que l'analyse de table vous oblige à regarder N lignes (où N est le nombre de lignes), la recherche binaire ne nécessite que de regarder les entrées d'index log-n, dans le pire des cas. Wow, c'est sûr beaucoup plus facile!

Bien sûr, si vous avez cet index et que vous ajoutez des lignes à la table (à la fin, puisque c'est ainsi que fonctionne notre table conceptuelle), vous devez mettre à jour l'index à chaque fois. Vous faites donc un peu plus de travail pendant que vous écrivez de nouvelles lignes, mais vous économisez une tonne de temps lorsque vous recherchez quelque chose.

Ainsi, en général, l'indexation crée un compromis entre l'efficacité de lecture et l'efficacité d'écriture. Sans index, les insertions peuvent être très rapides - le moteur de base de données ajoute simplement une ligne à la table. Lorsque vous ajoutez des index, le moteur doit mettre à jour chaque index lors de l'insertion.

En revanche, les lectures deviennent beaucoup plus rapides.

J'espère que cela couvre vos deux premières questions (comme d'autres l'ont répondu - vous devez trouver le bon équilibre).

Votre troisième scénario est un peu plus compliqué. Si vous utilisez LIKE, les moteurs d'indexation vous aideront généralement avec votre vitesse de lecture jusqu'au premier "%". En d'autres termes, si vous SÉLECTIONNEZ O WH la colonne COMME 'foo% bar%', la base de données utilisera l'index pour trouver toutes les lignes où la colonne commence par "foo", puis devra analyser cet ensemble de lignes intermédiaire pour trouver le sous-ensemble qui contient "bar". SELECT ... WHERE colonne LIKE '% bar%' ne peut pas utiliser l'index. J'espère que vous pouvez voir pourquoi.

Enfin, vous devez commencer à penser aux index sur plusieurs colonnes. Le concept est le même et se comporte de la même manière que les éléments LIKE - essentiellement, si vous avez un index sur (a, b, c), le moteur continuera à utiliser l'index de gauche à droite du mieux qu'il peut. Ainsi, une recherche sur la colonne a pourrait utiliser l'index (a, b, c), tout comme une sur (a, b). Cependant, le moteur devrait effectuer une analyse complète de la table si vous recherchiez O = b = 5 ET c = 1)

J'espère que cela vous aidera à jeter un peu de lumière, mais je dois répéter que vous feriez mieux de passer quelques heures à fouiller pour trouver de bons articles qui expliquent ces choses en profondeur. C'est également une bonne idée de lire la documentation de votre serveur de base de données particulier. La façon dont les index sont implémentés et utilisés par les planificateurs de requêtes peut varier assez largement.


10
Et les FULLTEXTindex? Peuvent-ils aider avec des conditions comme LIKE '%bar%'?
septembre 2013

2
@Septagram - FULLTEXTpeut aider avec cette requête s'il bar s'agit d'un "mot". FULLTEXTgère les mots, pas les sous-chaînes arbitraires (comme le LIKEfait).
Rick James

@timdev explicitement dans quelle partie a répondu la première question? Je peux détecter les deuxième et troisième questions auxquelles on a répondu dans la première et la deuxième partie (avant et après de J'espère que cela couvre vos deux premières questions ) de votre précieuse réponse
Manuel Jordan

1
@ManuelJordan - Il n'y a pas de réponse simple à la première question. Cela dépend de la façon dont vous souhaitez équilibrer les compromis dans le contexte de l'utilisation prévue (ou encore mieux, observée).
timdev

57

Découvrez des présentations comme More Mastering the Art of Indexing .

Mise à jour 12/2012: J'ai posté une nouvelle présentation de la mienne: Comment concevoir des index, vraiment . Je l'ai présenté en octobre 2012 au ZendCon de Santa Clara et en décembre 2012 au Percona Live London.

La conception des meilleurs index est un processus qui doit correspondre aux requêtes que vous exécutez dans votre application.

Il est difficile de recommander des règles générales sur les colonnes qu'il est préférable d'indexer, ou si vous devez indexer toutes les colonnes, pas de colonnes, quels index doivent s'étendre sur plusieurs colonnes, etc. Cela dépend des requêtes que vous devez exécuter.

Oui, il y a des frais généraux, vous ne devez donc pas créer inutilement des index. Mais vous devez créer les indices qui donnent avantage aux requêtes dont vous avez besoin pour exécuter rapidement. Les frais généraux d'un indice sont généralement largement compensés par son avantage.

Pour une colonne qui est VARCHAR (2500), vous souhaiterez probablement utiliser un index FULLTEXT ou un index de préfixe:

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

Notez qu'un index conventionnel ne peut pas aider si vous recherchez des mots qui peuvent être au milieu de ce long varchar. Pour cela, utilisez un index fulltext.


3
Merci beaucoup. slideshare.net/matsunobu/… a été très utile en effet.
Bishal Paudel



1
Présentation étonnante (celle de 2012), vraiment compris tout l'intérêt des index.
DarkteK

46

Je ne répéterai pas certains des bons conseils dans d'autres réponses, mais ajouterai:

Indices composés

Vous pouvez créer des indices composés - un index qui comprend plusieurs colonnes. MySQL peut les utiliser de gauche à droite . Donc si vous avez:

Table A
Id
Name
Category
Age
Description

si vous avez un index composé qui inclut Nom / Catégorie / Âge dans cet ordre, ces clauses WHERE utiliseraient l'index:

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

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

mais

WHERE Category='A' and Age > 18

n'utiliserait pas cet index car tout doit être utilisé de gauche à droite.

Explique

Utilisez Explain / Explain Extended pour comprendre quels indices sont disponibles pour MySQL et lequel il sélectionne réellement. MySQL n'utilisera UNE clé par requête .

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

Journal des requêtes lentes

Activez le journal des requêtes lentes pour voir quelles requêtes s'exécutent lentement.

Colonnes larges

Si vous avez une large colonne où LA PLUPART de la distinction se produit dans les premiers caractères, vous ne pouvez utiliser que les N premiers caractères de votre index. Exemple: Nous avons une colonne ReferenceNumber définie comme varchar (255) mais 97% des cas, le numéro de référence est de 10 caractères ou moins. J'ai changé l'index pour ne regarder que les 10 premiers caractères et amélioré un peu les performances.


J'ai une question sur la dernière partie. J'ai lu quelque part que si vous créez une colonne avec VARCHAR, vous devez toujours la définir à 255. Maintenant, vous avez dit qu'un index défini sur ce type de colonne pouvait se limiter à ne regarder que les 10 premiers caractères. Comment pouvez-vous faire exactement cela?
AlexioVay

20

Si une table a six colonnes et qu'elles sont toutes consultables, dois-je les indexer toutes ou aucune

Recherchez-vous champ par champ ou certaines recherches utilisent-elles plusieurs champs? Sur quels champs sont les plus recherchés? Quels sont les types de champs? (L'index fonctionne mieux sur les INT que sur les VARCHAR par exemple) Avez-vous essayé d'utiliser EXPLAIN sur les requêtes en cours d'exécution?

Quels sont les impacts négatifs sur les performances de l'indexation

Les MISES À JOUR et INSÉRER seront plus lentes. Il y a aussi les besoins d'espace de stockage supplémentaires, mais cela n'a généralement pas d'importance de nos jours.

Si j'ai une colonne VARCHAR 2500 qui peut être recherchée à partir de parties de mon site, dois-je l'indexer

Non, à moins que ce soit UNIQUE (ce qui signifie qu'il est déjà indexé) ou que vous ne recherchez que des correspondances exactes sur ce champ (sans utiliser LIKE ou la recherche plein texte de mySQL).

En général, je mets un index sur tous les champs que je vais rechercher ou sélectionner en utilisant une clause WHERE

J'indexerais normalement les champs qui sont les plus interrogés, puis les INT / BOOLEANs / ENUMs plutôt que les champs qui sont des VARCHARS. N'oubliez pas, vous devez souvent créer un index sur des champs combinés plutôt qu'un index sur un champ individuel. Utilisez EXPLAIN et vérifiez le journal lent.


11

Charger les données efficacement : les index accélèrent les récupérations mais ralentissent les insertions et les suppressions, ainsi que les mises à jour des valeurs dans les colonnes indexées. Autrement dit, les index ralentissent la plupart des opérations qui impliquent l'écriture. Cela se produit car l'écriture d'une ligne nécessite non seulement d'écrire la ligne de données, mais également de modifier les index. Plus il y a d'index dans une table, plus de modifications doivent être apportées et plus la dégradation moyenne des performances est importante. La plupart des tables reçoivent de nombreuses lectures et peu d'écritures, mais pour une table avec un pourcentage élevé d'écritures, le coût de la mise à jour de l'index peut être important.

Évitez les index : si vous n'avez pas besoin d'un index particulier pour améliorer les performances des requêtes, ne le créez pas.

Espace disque : un index occupe de l'espace disque et plusieurs index occupent en conséquence plus d'espace. Cela peut vous amener à atteindre une limite de taille de table plus rapidement que s'il n'y a pas d'index. Évitez les index dans la mesure du possible.

À emporter: ne pas trop indexer


5

En général, les index permettent d'accélérer la recherche dans la base de données, ayant l'inconvénient d'utiliser de l'espace disque supplémentaire et de ralentir les requêtes INSERT/ UPDATE/ DELETE. Utilisez EXPLAINet lisez les résultats pour savoir quand MySQL utilise vos indices.

Si une table comporte six colonnes et qu'elles sont toutes consultables, dois-je les indexer toutes ou aucune d'entre elles?

L'indexation des six colonnes n'est pas toujours la meilleure pratique.

(a) Allez-vous utiliser l'une de ces colonnes lors de la recherche d'informations spécifiques?

(b) Quelle est la sélectivité de ces colonnes (combien de valeurs distinctes y a-t-il en mémoire, par rapport au nombre total d'enregistrements sur la table)?

MySQL utilise un optimiseur basé sur les coûts, qui essaie de trouver le chemin "le moins cher" lors de l'exécution d'une requête. Et les domaines à faible sélectivité ne sont pas de bons candidats.

Quels sont les impacts négatifs sur les performances de l'indexation?

Déjà répondu: espace disque supplémentaire, performances inférieures lors de l'insertion - mise à jour - suppression.

Si j'ai une colonne VARCHAR 2500 qui peut être recherchée à partir de parties de mon site, dois-je l'indexer?

Essayez l' index FULLTEXT .


4

1/2) Les index accélèrent certaines opérations de sélection mais ralentissent d'autres opérations comme l'insertion, la mise à jour et la suppression. Cela peut être un bon équilibre.

3) utilisez un index de texte intégral ou peut-être un sphinx


Pour éviter, slow down other operations like insert, update and deletesvous pouvez utiliser l' START TRANSACTION; YOUR CODE HERE; COMMIT option Qui peut aider à éviter slowing downles autres opérations, car elle ne vérifie qu'une seule fois les contraintes. CAVEAT: Si vous utilisez REPLACE INTOet votre SQL_MODE<> STRICT_ALL_TABLESOU TRADITIONALLe Bulk Loadignorera le remplacement et insérera des doublons.
JayRizzo

Les transactions ne sont pas prises en charge dans tous les moteurs MySQL. AFAIK, les transactions ralentissent les opérations DB, même si elles ne sont utilisées qu'implicitement. Ce que nous devons concevoir en fonction des performances réelles est un moyen semi-automatique de profiler (mesurer les performances) de divers choix d'optimisation, y compris les index et les transactions.
David Spector,
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.