Comment fonctionnent les index MySQL?

402

Je suis vraiment intéressé par le fonctionnement des index MySQL, plus précisément, comment peuvent-ils renvoyer les données demandées sans scanner toute la table?

C'est hors sujet, je sais, mais s'il y a quelqu'un qui pourrait m'expliquer cela en détail, je serais très, très reconnaissant.

good_evening
la source
C'est une question très large. Si vous avez un exemple spécifique de requête qui n'utilisera pas d'index et que vous ne savez pas pourquoi, vous pouvez le publier et des personnes pourraient vous aider.
Hammerite
SELECT * FROM members WHERE id = '1'- alors pourquoi avec index ça marche plus vite? Que fait cet indice ici?
good_evening
2
Cela ressemble à une requête qui recherche uniquement un enregistrement indexé spécifique (peut-être identifié par la clé primaire). L'index rend cela plus rapide car il est stocké en mémoire, la ligne d'index correspondante peut être consultée et elle contient un pointeur vers l'endroit où les données réelles sont stockées. MySQL peut donc aller à l'emplacement exact de la table sans avoir à scanner la table.
Hammerite
Très bien merci!
Courses de légèreté en orbite

Réponses:

513

Fondamentalement, un index sur une table fonctionne comme un index dans un livre (c'est de là que vient le nom):

Disons que vous avez un livre sur les bases de données et que vous souhaitez trouver des informations sur, disons, le stockage. Sans index (en supposant qu'aucune autre aide, telle qu'une table des matières), vous devriez parcourir les pages une par une, jusqu'à ce que vous trouviez le sujet (c'est un full table scan). D'un autre côté, un index a une liste de mots-clés, vous devriez donc consulter l'index et voir ce qui storageest mentionné aux pages 113-120,231 et 354. Ensuite, vous pouvez retourner directement à ces pages, sans rechercher (c'est une recherche avec un index, un peu plus rapide).

Bien sûr, l'utilité de l'index dépend de beaucoup de choses - quelques exemples, en utilisant la comparaison ci-dessus:

  • si vous aviez un livre sur les bases de données et indexiez le mot "base de données", vous verriez qu'il est mentionné aux pages 1-59,61-290 et 292 à 400. Dans ce cas, l'index n'est pas d'une grande aide et il pourrait être plus rapide pour parcourir les pages une par une (dans une base de données, c'est une "mauvaise sélectivité").
  • Pour un livre de 10 pages, cela n'a aucun sens de faire un index, car vous pouvez vous retrouver avec un livre de 10 pages préfixé par un index de 5 pages, ce qui est tout simplement stupide - il suffit de numériser les 10 pages et d'en finir avec .
  • L'index doit également être utile - il est généralement inutile d'indexer par exemple la fréquence de la lettre "L" par page.
Piskvor a quitté le bâtiment
la source
3
Vous expliquez ce que c'est, pas comment cela fonctionne techniquement en interne.
Tutu Kumari
@Tutu Kumari: Voir les révisions de la question; n'hésitez pas à réviser également la réponse pour l'adapter à la question actuelle (notez les différents moteurs et types d'index - voir par exemple la documentation ici: dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html )
Piskvor a quitté le bâtiment le
259

La première chose que vous devez savoir est que les index sont un moyen d'éviter d'analyser la table complète pour obtenir le résultat que vous recherchez.

Il existe différents types d'index et ils sont implémentés dans la couche de stockage, il n'y a donc pas de norme entre eux et ils dépendent également du moteur de stockage que vous utilisez.

InnoDB et l'indice B + Tree

Pour InnoDB, le type d'index le plus courant est l'index B + Tree, qui stocke les éléments dans un ordre trié. De plus, vous n'avez pas besoin d'accéder à la vraie table pour obtenir les valeurs indexées, ce qui accélère considérablement le retour de votre requête.

Le "problème" de ce type d'index est que vous devez rechercher la valeur la plus à gauche pour utiliser l'index. Par conséquent, si votre index comporte deux colonnes, par exemple nom_prénom et prénom, l'ordre dans lequel vous interrogez ces champs est très important .

Donc, étant donné le tableau suivant:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

Cette requête profiterait de l'index:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

Mais le suivant ne serait pas

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

Parce que vous interrogez la first_namecolonne en premier et que ce n'est pas la colonne la plus à gauche de l'index.

Ce dernier exemple est encore pire:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

Parce que maintenant, vous comparez la partie la plus à droite du champ le plus à droite dans l'index.

L'index de hachage

Il s'agit d'un type d'index différent que, malheureusement, seul le backend mémoire prend en charge. Il est rapide comme l'éclair mais utile uniquement pour les recherches complètes, ce qui signifie que vous ne pouvez pas l'utiliser pour des opérations telles que >, <ou LIKE.

Comme il ne fonctionne que pour le backend mémoire, vous ne l'utiliserez probablement pas très souvent. Le cas principal auquel je peux penser en ce moment est celui où vous créez une table temporaire dans la mémoire avec un ensemble de résultats d'une autre sélection et effectuez beaucoup d'autres sélections dans cette table temporaire en utilisant des index de hachage.

Si vous avez un grand VARCHARchamp, vous pouvez "émuler" l'utilisation d'un index de hachage lorsque vous utilisez un arbre B, en créant une autre colonne et en y enregistrant un hachage de grande valeur. Disons que vous stockez une URL dans un champ et que les valeurs sont assez grandes. Vous pouvez également créer un champ entier appelé url_hashet utiliser une fonction de hachage comme CRC32ou toute autre fonction de hachage pour hacher l'URL lors de son insertion. Et puis, lorsque vous devez rechercher cette valeur, vous pouvez faire quelque chose comme ceci:

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

Le problème avec l'exemple ci-dessus est que, puisque la CRC32fonction génère un hachage assez petit, vous vous retrouverez avec beaucoup de collisions dans les valeurs hachées. Si vous avez besoin de valeurs exactes, vous pouvez résoudre ce problème en procédant comme suit:

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

Il vaut toujours la peine de hacher les choses même si le nombre de collisions est élevé, car vous n'effectuerez que la deuxième comparaison (la chaîne) avec les hachages répétés.

Malheureusement, en utilisant cette technique, vous devez toujours frapper la table pour comparer le urlchamp.

Emballer

Quelques faits que vous pouvez considérer chaque fois que vous souhaitez parler d'optimisation:

  1. La comparaison d'entiers est bien plus rapide que la comparaison de chaînes. Il peut être illustré par l'exemple de l'émulation de l'indice de hachage dans InnoDB.

  2. Peut-être que l'ajout d'étapes supplémentaires dans un processus le rend plus rapide et non plus lent. Cela peut être illustré par le fait que vous pouvez optimiser un SELECTen le divisant en deux étapes, en faisant que la première stocke des valeurs dans une table en mémoire nouvellement créée, puis en exécutant les requêtes plus lourdes sur cette deuxième table.

MySQL a aussi d'autres index, mais je pense que l'arbre B + est le plus utilisé de tous les temps et celui de hachage est une bonne chose à savoir, mais vous pouvez trouver les autres dans la documentation MySQL .

Je vous recommande fortement de lire le livre "High Performance MySQL", la réponse ci-dessus était définitivement basée sur son chapitre sur les index.

clarete
la source
2
Les requêtes suivantes auront-elles un avantage dans le cas ci-dessus? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Akshay Taru
1
Le premier testament, la deuxième requête ne le sera pas. Utilisez EXPLAIN: dev.mysql.com/doc/refman/5.5/en/explain.html Pour indexer la deuxième requête avec MySQL, vous devez utiliser FULLTEXT INDEX: dev.mysql.com/doc/refman/5.5/en/fulltext- search.html
Emilio Nicolás
5
Je vous ai voté parce que vous étiez à 127 et la réponse n ° 1 était à 256. Je ne pouvais pas éviter de tout rendre agréable et propre, binaire.
pbarney
Ce sont de nouvelles informations pour moi "pour que vous interrogiez ces champs compte beaucoup." Merci.
Khatri
1
@pbarney après trois ans, ils sont près de 256 et 512 respectivement, c'est ce que j'appelle une augmentation binaire!
nanocv
43

Fondamentalement, un index est une carte de toutes vos clés qui est triée dans l'ordre. Avec une liste dans l'ordre, puis au lieu de vérifier chaque clé, il peut faire quelque chose comme ceci:

1: Aller au milieu de la liste - est-il supérieur ou inférieur à ce que je recherche?

2: Si plus haut, allez à mi-chemin entre le milieu et le bas, si bas, moyen et haut

3: Est-il supérieur ou inférieur? Aller à nouveau au milieu, etc.

En utilisant cette logique, vous pouvez trouver un élément dans une liste triée en environ 7 étapes, au lieu de vérifier chaque élément.

Évidemment, il y a des complexités, mais cela vous donne l'idée de base.

Joshua
la source
29
C'est ce qu'on appelle la recherche binaire.
ddlshack
Merci, enfin une réponse qui explique pourquoi c'est plus rapide et pas seulement comment la base de données fonctionne avec les index.
Gershon Herczeg
Le nombre réel d'étapes dépend fortement des données - nombre de valeurs uniques et distribution sur votre gamme. 7 est le maximum théorique pour 100 valeurs. Discussion complète sur la façon de calculer le nombre d'étapes ici stackoverflow.com/questions/10571170/…
Joshua
L'index MySQL le plus courant est un arbre B + qui fonctionne de manière similaire à une recherche binaire mais pas tout à fait la même chose. La complexité algorithmique est la même, mais la façon dont elle recherche ne l'est pas. Voir en.wikipedia.org/wiki/B-tree
Matt
4

Jetez un œil à ce lien: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

La façon dont ils fonctionnent est trop vaste pour être abordée dans un seul message SO.

Voici l' une des meilleures explications des index que j'ai vues. Malheureusement, c'est pour SQL Server et non MySQL. Je ne sais pas à quel point les deux sont similaires ...

Abe Miessler
la source
2
Bel article. Je ne connais pas SQL Server, mais le fonctionnement de base semble très similaire. (métanote: la désactivation des styles CSS dans le 2ème article lié révèle le contenu)
Piskvor a quitté le bâtiment
3

Regardez ces vidéos pour plus de détails sur l'indexation

Indexation simple Vous pouvez créer un index unique sur une table. Un index unique signifie que deux lignes ne peuvent pas avoir la même valeur d'index. Voici la syntaxe pour créer un index sur une table

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

Vous pouvez utiliser une ou plusieurs colonnes pour créer un index. Par exemple, nous pouvons créer un index sur l' tutorials_tblutilisation de tutorial_author.

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

Vous pouvez créer un index simple sur une table. Omettez simplement le mot-clé UNIQUE de la requête pour créer un index simple. Un index simple permet de dupliquer des valeurs dans une table.

Si vous souhaitez indexer les valeurs d'une colonne dans l'ordre décroissant, vous pouvez ajouter le mot réservé DESC après le nom de la colonne.

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)
shahirnana
la source
1
Bienvenue dans Stack Overflow! J'ai remarqué que toutes vos réponses renvoient vers vos propres vidéos. Veuillez noter que l'autopromotion manifeste n'est pas autorisée .
SL Barth - Reinstate Monica
Il veut promouvoir ses vidéos. LOL
Ilyas karim
1

Je veux ajouter mes 2 cents. Je suis loin d'être un expert en bases de données, mais j'ai récemment lu un peu sur ce sujet; assez pour moi d'essayer de donner un ELI5. Alors, voici l'explication du profane.


Je le comprends comme tel qu'un index est comme un mini-miroir de votre table, un peu comme un tableau associatif. Si vous l'alimentez avec une clé correspondante, vous pouvez simplement passer à cette ligne dans une "commande".

Mais si vous n'aviez pas cet index / tableau, l'interpréteur de requêtes doit utiliser une boucle for pour parcourir toutes les lignes et rechercher une correspondance (l'analyse complète de la table).

Avoir un index a «l'inconvénient» du stockage supplémentaire (pour ce mini-miroir), en échange de «l'avantage» de rechercher du contenu plus rapidement.

Notez que (en fonction de votre moteur de base de données) la création de clés primaires, étrangères ou uniques configure également automatiquement un index respectif. Ce même principe est essentiellement pourquoi et comment ces clés fonctionnent.

WoodrowShigeru
la source
1

Ajout d'une représentation visuelle à la liste des réponses. entrez la description de l'image ici

MySQL utilise une couche supplémentaire d'indirection: les enregistrements d'index secondaire pointent vers les enregistrements d'index principal et l'index principal lui-même contient les emplacements de ligne sur le disque. Si un décalage de ligne change, seul l'index principal doit être mis à jour.

Mise en garde: la structure des données du disque semble plate dans le diagramme mais est en réalité une arborescence B +.

Source: lien

Anush
la source
1

Dans MySQL InnoDB, il existe deux types d'index.

  1. Clé primaire appelée index clusterisé. Les mots-clés d'index sont stockés avec des données d'enregistrement réelles dans le nœud feuille B + Tree.

  2. Clé secondaire qui est un index non clusterisé. Ces index stockent uniquement les mots clés de la clé primaire avec leurs propres mots clés d'index dans le nœud feuille B + Tree. Ainsi, lors de la recherche à partir d'un index secondaire, il trouvera d'abord ses mots clés d'index de clé primaire et analysera l'arborescence B + de la clé primaire pour trouver les enregistrements de données réels. Cela rendra l'index secondaire plus lent que la recherche d'index primaire. Cependant, si les selectcolonnes sont toutes dans l'index secondaire, il n'est pas nécessaire de rechercher à nouveau l'index principal B + Tree. C'est ce qu'on appelle l'indice de couverture.

sendon1982
la source