J'ai une table MySQL pour laquelle je fais très fréquemment des requêtes SELECT x, y, z FROM table WHERE x LIKE '%text%' OR y LIKE '%text%' OR z LIKE '%text%'
. Un indice quelconque aiderait-il à accélérer les choses?
Il y a quelques millions d'enregistrements dans la table. Si quelque chose accélère la recherche, cela affectera-t-il sérieusement l'utilisation du disque par les fichiers de base de données et la vitesse des déclarations INSERT
et DELETE
? (aucune UPDATE
n'est jamais effectuée)
Mettre à jour: Rapidement après avoir posté, j'ai vu beaucoup d'informations et de discussions sur la façon dont LIKE
est utilisé dans la requête; Je tiens à souligner que la solution doit utilisez LIKE '%text%'
(c’est-à-dire que le texte que je cherche est ajouté et précédé d’un caractère générique%). La base de données doit également être locale, pour de nombreuses raisons, notamment la sécurité.
Un index n'accélère pas la requête, car pour les colonnes textuelles, les index fonctionnent en indexant N caractères à partir de la gauche. Quand vous aimez LIKE '% text%', il ne peut pas utiliser l'index car il peut y avoir un nombre variable de caractères avant le texte.
Ce que vous devriez faire, ce n’est pas du tout utiliser une requête de ce type. Au lieu de cela, vous devriez utiliser quelque chose comme FTS (Full Text Search) que MySQL supporte pour les tables MyISAM. Il est également assez facile de créer ce système d’indexation vous-même pour les tables autres que MyISAM. Vous avez simplement besoin d’une table d’indexation séparée dans laquelle vous stockez les mots et leurs identifiants pertinents dans la table.
Un index ne facilitera pas la correspondance de texte avec un caractère générique de premier plan, un index peut être utilisé pour:
LIKE 'text%'
Mais je suppose que ça ne va pas le couper. Pour ce type de requête, vous devriez vraiment faire appel à un fournisseur de recherche en texte intégral si vous souhaitez mettre à l'échelle la quantité d'enregistrements que vous pouvez rechercher. Mon fournisseur préféré est Sphinx , très complet/rapide, etc. Lucene pourrait également valoir le coup d'oeil. Un index de texte intégral sur une table MyISAM fonctionnera également, mais poursuivre en dernier recours sur MyISAM pour toute base de données contenant beaucoup d'écritures n'est pas une bonne idée.
Un index peut non être utilisé pour accélérer les requêtes lorsque les critères de recherche commencent par un caractère générique:
LIKE '%text%'
Un index peut (et peut être, en fonction de la sélectivité) utilisé pour les termes de recherche de la forme:
LIKE 'text%'
Peut-être que vous pouvez essayer de mettre à jour mysql5.1 vers mysql5.7.
J'ai environ 70 000 enregistrements. Et exécutez SQL suivant:
select * from comics where name like '%test%';
Cela prend 2000ms dans mysql5.1 . Et cela prend 200ms dans mysql5.7 ou mysql5.6.
Autrement:
Vous pouvez conserver les colonnes calculées avec ces chaînes REVERSEd et utiliser
SELECT x, y, z FROM table WHERE x LIKE 'text%' OR y LIKE 'text%' OR z LIKE 'text%' OR xRev LIKE 'txet%' OR yRev LIKE 'txet%' OR zRev LIKE 'txet%'
Exemple de comment ajouter une colonne persistante stockée
ALTER TABLE table ADD COLUMN xRev VARCHAR(N) GENERATED ALWAYS AS REVERSE(x) stored;
puis créez un index sur xRev
, yRev
etc.
Une autre alternative pour éviter les analyses de table complètes consiste à sélectionner des sous-chaînes et à les vérifier dans l'instruction having:
SELECT
al3.article_number,
SUBSTR(al3.article_number, 2, 3) AS art_nr_substr,
SUBSTR(al3.article_number, 1, 3) AS art_nr_substr2,
al1.*
FROM
t1 al1
INNER JOIN t2 al2 ON al2.t1_id = al1.id
INNER JOIN t3 al3 ON al3.id = al2.t3_id
WHERE
al1.created_at > '2018-05-29'
HAVING
(art_nr_substr = "FLA" OR art_nr_substr = 'VKV' OR art_nr_subst2 = 'PBR');