web-dev-qa-db-fra.com

INDEX possible sur un champ VARCHAR dans MySql

Je travaille dans une base de données MySql, avec une table comme celle-ci:

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... et je dois faire beaucoup de requêtes comme celle-ci (avec 5-10 chaînes dans la liste) :

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

Il y aura environ 24.000.000 lignes uniques

1) Dois-je utiliser une touche FULLTEXT ou et INDEX pour ma VARCHAR(150)?
2) Si j'augmente les caractères de 150 à 220 ou 250 ... cela ferait-il une grande différence? (Existe-t-il un moyen de le calculer?)
) Comme je l'ai dit, ils vont être uniques, donc myField devrait être un - TOUCHE PRIMAIRE. N'est-il pas rare d'ajouter une CLÉ PRIMAIRE à un champ qui est déjà un VARCHAR INDEX/FULLTEXT?

43
Mark Tower

SUGGESTION # 1: Indexation standard

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

Si vous indexez comme ceci, vous pouvez soit rechercher la chaîne entière, soit effectuer des recherches LIKE orientées vers la gauche

SUGGESTION # 2: Indexation intégrale

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

Vous pouvez utiliser efficacement les recherches de mots clés individuels ainsi que des phrases entières. Vous devrez définir une liste de mots vides personnalisée car MySQL n'indexera pas 543 mots .

Voici mes autres articles des deux dernières années sur les index FULLTEXT

SUGGESTION # 3: Indexation de hachage

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

Si vous recherchez une valeur spécifique et que ces valeurs peuvent avoir des longueurs bien au-delà de 32 caractères, vous pouvez stocker la valeur de hachage:

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

De cette façon, il vous suffit de rechercher des valeurs de hachage pour récupérer les résultats

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

Essaie !!!

69
RolandoMySQLDBA

MySQL vous permet de définir un index préfixé, ce qui signifie que vous définissez les premiers N caractères de la chaîne d'origine à indexer, et l'astuce consiste à choisir un nombre N suffisamment long pour donner une bonne sélectivité, mais assez court pour économiser de l'espace. Le préfixe doit être suffisamment long pour rendre l'index presque aussi utile qu'il le serait si vous aviez indexé toute la colonne.

Avant d'aller plus loin, définissons quelques termes importants. La sélectivité d'index est le rapport de 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 indexons uniquement le premier caractère (N = 1), la table d'index ressemblera au tableau suivant:

+---------------+-----------+
| 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 résultera en une sélectivité d'index maximale.

Vous pouvez effectuer deux calculs pour votre table de base de données. Je ferai une démonstration sur le ce vidage de base de données .

Disons que nous voulons ajouter la colonne last_name dans la table salariés à l'index, et nous voulons définir le plus petit nombre [~ # ~] n [~ # ~] qui produira la meilleure sélectivité d'index.

Identifions d'abord 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 voir, le nom de famille Baba est le plus fréquent. Maintenant, nous allons trouver les préfixes last_name les plus fréquents, en commençant par les préfixes à 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 les mêmes que dans l'exemple précédent.

Voici les résultats 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 faire l'index sur la colonne last_name avec l'indexation des 10 premiers caractères seulement. Dans la colonne de définition de table last_name est défini comme VARCHAR(16), ce qui signifie que nous avons enregistré 6 octets (ou plus s'il y a des caractères UTF8 dans le nom de famille) 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 tableau contient des millions de lignes.

Vous pouvez lire d'autres façons de calculer le nombre de [~ # ~] n [~ # ~] dans mon article Index préfixés dans MySQL .

L'utilisation des 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 dans le post Comment choisir le bon type de données pour une clé primaire dans la base de données MySQL

18
Mr.M