MySQL vous permet de définir un index préfixé, ce qui signifie que vous définissez les N premiers caractères de la chaîne d'origine à indexer. L'astuce consiste à choisir un nombre N suffisamment long pour permettre une bonne sélectivité, mais suffisamment court pour économiser de l'espace. Le préfixe doit être suffisamment long pour rendre l'index presque aussi utile que si vous aviez indexé la colonne entière.
Avant d'aller plus loin, définissons quelques termes importants. La sélectivité d'index est le rapport entre le total des valeurs indexées distinctes et le nombre total de lignes . Voici un exemple de table de test:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Si nous n'indexons que le premier caractère (N = 1), alors la table d'index ressemblera à la table suivante:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
Dans ce cas, la sélectivité de l’indice est égale à IS = 1/3 = 0,33.
Voyons maintenant ce qui se passera si nous augmentons le nombre de caractères indexés à deux (N = 2).
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
Dans ce scénario, IS = 2/3 = 0.66, ce qui signifie que nous avons augmenté la sélectivité de l’indice, mais nous avons également augmenté la taille de l’indice. L'astuce consiste à trouver le nombre minimal N qui aboutira à la sélectivité maximale de l' index .
Il existe deux approches pour effectuer des calculs pour votre table de base de données. Je vais faire une démonstration sur le dump de cette base de données .
Supposons que nous voulions ajouter la colonne last_name dans la table employee à l'index et définir le plus petit nombre N qui produirait la meilleure sélectivité pour l'index.
Premièrement, identifions les noms de famille les plus fréquents:
select count(*) as cnt, last_name from employees group by employees.last_name order by cnt
+-----+-------------+
| cnt | last_name |
+-----+-------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Farris |
| 222 | Sudbeck |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Neiman |
| 218 | Mandell |
| 218 | Masada |
| 217 | Boudaillier |
| 217 | Wendorf |
| 216 | Pettis |
| 216 | Solares |
| 216 | Mahnke |
+-----+-------------+
15 rows in set (0.64 sec)
Comme vous pouvez le constater, le nom de famille Baba est le plus fréquent. Nous allons maintenant rechercher les préfixes last_name les plus fréquents , en commençant par les préfixes de cinq lettres.
+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa |
| 758 | Mande |
| 711 | Schwa |
| 562 | Angel |
| 561 | Gecse |
| 555 | Delgr |
| 550 | Berna |
| 547 | Peter |
| 543 | Cappe |
| 539 | Stran |
| 534 | Canna |
| 485 | Georg |
| 417 | Neima |
| 398 | Petti |
| 398 | Duclo |
+-----+--------+
15 rows in set (0.55 sec)
Il y a beaucoup plus d'occurrences de chaque préfixe, ce qui signifie que nous devons augmenter le nombre N jusqu'à ce que les valeurs soient presque identiques à celles de l'exemple précédent.
Voici les résultats de la recherche pour N = 9
select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;
+-----+-----------+
| cnt | prefix |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudailli |
| 216 | Cummings |
| 216 | Pettis |
+-----+-----------+
Voici les résultats pour N = 10.
+-----+------------+
| cnt | prefix |
+-----+------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudaillie |
| 216 | Cummings |
| 216 | Pettis |
| 216 | Solares |
+-----+------------+
15 rows in set (0.56 sec)
Ce sont de très bons résultats. Cela signifie que nous pouvons créer une indexation sur la colonne last_name en n'indexant que les 10 premiers caractères. Dans la définition de table, la colonne nom_famille est définie comme VARCHAR(16)
, ce qui signifie que nous avons enregistré 6 octets (ou plus si le nom contient des caractères UTF8) par entrée. Dans ce tableau, il y a 1637 valeurs distinctes multipliées par 6 octets, soit environ 9 Ko, et imaginez comment ce nombre augmenterait si notre table contenait des millions de lignes.
Vous pouvez lire d’autres méthodes de calcul du nombre de N dans mon post Les index préfixés dans MySQL .
Utiliser les fonctions MD5 et SHA1 pour générer des valeurs qui devraient être indexées n’est pas non plus une bonne approche . Pourquoi? Lisez-le en post Comment choisir le bon type de données pour une clé primaire dans la base de données MySQL