web-dev-qa-db-fra.com

Est-il possible d'avoir un index basé sur les fonctions dans MySQL?

Je me souviens dans Oracle, il est possible d'indexer en fonction d'une fonction, par exemple SUBSTRING(id,1,8).

MySQL prend-il cela en charge? Sinon, existe-t-il une alternative?

55
user836026

Non, pas dans un sens général, je ne pense pas que même 5.6 (la dernière version lorsque cette réponse a été écrite pour la première fois) ait cette fonctionnalité. Il convient de noter que les versions 8.0.13 et supérieures prennent désormais en charge les index fonctionnels, ce qui vous permet d'obtenir ce dont vous avez besoin sans la méthode de déclenchement décrite ci-dessous.

Voir https://dev.mysql.com/doc/refman/8.0/en/create-index.html pour plus de détails à ce sujet.

Si vous utilisez une ancienne version de mysql, il est possible d'utiliser uniquement le début partie d'une colonne (cette fonctionnalité existe depuis longtemps), mais pas une commençant par le deuxième caractère ou les caractères suivants, ou toute autre fonction plus complexe.

Par exemple, ce qui suit crée un index en utilisant les cinq premiers caractères d'un nom:

create index name_first_five on cust_table (name(5));

Pour les expressions plus complexes, vous pouvez obtenir un effet similaire en ayant une autre colonne contenant les données indexables, puis en utilisant des déclencheurs d'insertion/mise à jour pour vous assurer qu'elle est remplie correctement.

À part l'espace perdu pour les données redondantes, c'est à peu près la même chose.

Et, bien qu'il viole techniquement 3NF, cela est atténué par l'utilisation de déclencheurs pour garder les données synchronisées (c'est quelque chose qui est souvent fait pour des performances supplémentaires).

49
paxdiablo

MySQL ne prend pas cela en charge, mais il existe une alternative.

1. Depuis MySQL 5.7.6

Vous pouvez utiliser une colonne générée automatiquement pour contenir la sous-chaîne avec un index dessus:

CREATE TABLE SomeTable (
    id CHAR(10),
    sub_id CHAR(8) AS SUBSTRING(id, 1, 8) STORED, INDEX(sub_id)
)

Comme Benjamin noté, InnoDB prend en charge les index secondaires sur les colonnes virtuelles afin que le mot-clé STORED puisse être omis. En fait, des index secondaires sur des colonnes virtuelles peuvent être préférables. Plus d'informations ici: Index secondaires et colonnes générées

2. Avant MySQL 5.7.6

Vous pouvez utiliser une colonne mise à jour par un déclencheur avec un index dessus:

CREATE TABLE SomeTable (
    id CHAR(10),
    sub_id CHAR(8) , INDEX(sub_id)
);

CREATE TRIGGER TR_SomeTable_INSERT_sub_id
    BEFORE INSERT
    ON SomeTable FOR EACH ROW 
    SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8);

CREATE TRIGGER TR_SomeTable_UPDATE_sub_id
    BEFORE UPDATE
    ON SomeTable FOR EACH ROW 
    SET NEW.sub_id = SUBSTRING(NEW.id, 1, 8);
30
axxis

Ceci est possible à partir de MySQL 5.7.5 en utilisant le nouveau Generated Columns .

15

Oui, nous pouvons créer un index fonctionnel dans MySQL. Cette fonctionnalité est disponible à partir de MySQL 8.0.13. (D'autres SGBDR ont cette fonctionnalité dans ses versions précédentes, mais MySQL l'a introduite dans sa version 8.0.13). Index fonctionnel

Ici, j'ai donné un exemple pour créer un index fonctionnel dans MySQL8.0

Telle est la requête

sélectionnez * dans app_user où month (createdOn) = 5;

mysql> sélectionnez * dans app_user où month (createdOn) = 5; 7e9e2b7bc2e9bde15504f6c5658458ab - 74322 lignes en jeu (5,01 s)

Il s'exécute pendant plus de 5 secondes pour récupérer les enregistrements 74322 même si j'ai un index sur la colonne createdOn. (L'indexation sur la colonne createdOn n'est pas utilisée par l'optimiseur car elle est masquée par la fonction month ())

Maintenant, j'ai créé un index fonctionnel sur la colonne en utilisant la syntaxe ci-dessous.

mysql> alter table app_user add index idx_month_createdon ((month (createdOn))); Requête OK, 0 lignes affectées (1 min 17,37 sec) Enregistrements: 0 Doublons: 0 Avertissements: 0

mysql> sélectionnez * dans app_user où month (createdOn) = 5; 7e9e2b7bc2e9bde15504f6c5658458ab - 74322 lignes en jeu (0,29 sec)

Après avoir créé l'index fonctionnel, il s'exécute en 0,29 secondes.

Il est difficile de trouver un document d'index fonctionnel sur le site Web de Mysql, c'est au nom de parties clés fonctionnelles

Et nous ne pouvons pas supprimer la colonne qui a un index fonctionnel. Pour y parvenir, nous devons d'abord supprimer l'indice fonctionnel.

mysql> alter table app_user drop column createdOn; Impossible de supprimer la colonne 'createdOn' car elle est utilisée par un index fonctionnel. Pour supprimer la colonne, vous devez supprimer l'index fonctionnel.

Si vous utilisez MySQL> 5.7.5, vous pouvez obtenir la même chose en utilisant colonnes générées .

1