Recherche en texte intégral chinois mysql de l'entrée à l'abandon

Comme une requête floue en correspondance complète ne peut pas utiliser l'index est toujours un problème épineux de requête SQL, la recherche en texte intégral mysql peut-elle vraiment résoudre ce problème?

Contexte

Récemment, j'ai rencontré un problème d'optimisation des requêtes dans mon travail. Le SQL simplifié est le suivant:

SELECT
	* 
FROM
	wxswj_nsrxx 
WHERE
	nsrmc LIKE '%东鹏%' 
	OR nsrsbh LIKE '%东鹏%' 
	OR shxydm LIKE '%东鹏%';

Questions:
1. Une requête floue à correspondance complète est utilisée
2. Le mot clé OR est utilisé

Évidemment, une telle requête ne peut pas être indexée, et comme le volume de données de la table est très important, avec plus de 5 millions de données, la vitesse de réponse de l'ensemble de la requête est très insatisfaisante.

Recherche de texte intégral chinois en pratique

Instructions pour l'insertion de segmentation ngram:
https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html ajouter la description du lien

1. Idée d'optimisation:
la requête de correspondance floue chinoise implique principalement la segmentation de mots et la récupération de texte intégral, et il existe un type d'index dans mysql qui est l'index de texte intégral FULLTEXT . Je veux donc résoudre le problème de la requête floue de correspondance complète dans mysql grâce à l'indexation de texte intégral.

2. Description:
avant MySQL 5.7.6, l'indexation de texte intégral ne prend en charge que l'indexation de texte intégral en anglais, pas l'indexation de texte intégral en chinois. Vous devez utiliser un segmenteur de mots pour prétraiter les paragraphes chinois en mots, puis les stocker dans la base de données.
À partir de MySQL 5.7.6, MySQL a un analyseur de texte intégral ngram intégré pour prendre en charge la segmentation des mots chinois.

3. Affichez la version actuelle de la base de données:

select version() from dual;

Le résultat est 5.7.28, qui prend en charge la recherche en texte intégral chinois

4. Restrictions
sur la recherche en texte intégral: les index FULLTEXT sont créés sur des colonnes textuelles (colonnes CHAR, VARCHAR ou TEXT). Les
index en texte intégral ne peuvent être créés que sur des colonnes CHAR, VARCHAR ou TEXT.
Chaque table ne peut avoir qu'un seul index de recherche en texte intégral
. L' index de recherche en texte intégral composé de plusieurs colonnes doit utiliser le même jeu de caractères et le même classement.

5.
Avant de fermer l' optimisation SQL du cache de requêtes , le cache de requêtes est généralement fermé:
SHOW VARIABLES LIKE'query_cache% ';
set global query_cache_size = 0;
set global query_cache_type = 0;

AFFICHER LES VARIABLES COMME 'query_cache%';

6. Créez un index de texte intégral

ALTER TABLE `wxswj`.`wxswj_nsrxx`  ADD FULLTEXT INDEX `ft_index`(`nsrmc`,`nsrsbh`,`shxydm`) WITH PARSER ngram;

7. Utilisez l'index de texte intégral Utilisez l'index de texte intégral
via l'instruction ** MATCH (col1, col2, ...) AGAINST (expr [search_modifier]) **.

SELECT
	* 
FROM
	wxswj_nsrxx MATCH ( `nsrmc`, `nsrsbh`, `shxydm` ) against ( '东鹏' IN boolean MODE )

Les trois champs de 东鹏correspondance de flou ,, sont utilisés ici nsrmc, nsrsbhet l' enregistrement correspondant est renvoyé si l' shxydmun des champs contient la clé de requête 东鹏.

8. Le plan d'exécution de la requête
Insérez la description de l'image ici
utilise une nouvelle recherche combinée en texte intégral et ref atteint le niveau const

9. Effet d'optimisation Les
performances des requêtes ont été améliorées plus de 100 fois.

fosse

Jusqu'à présent, tout semble être très bon, mais bientôt la fosse est apparue.
Lorsque le mot-clé de requête est trop long, une exception se produit?

Question 1: La requête FTS dépasse la limite du cache des résultats
lorsqu'une condition de requête relativement longue est utilisée pour correspondre à la requête ou même exécuter le plan de requête, une exception se produit:

188 - FTS query exceeds result cache limit

Explication de l'exception sur le site officiel de mysql:
https://bugs.mysql.com/bug.php?id=86036

Chaque requête de recherche en texte intégral ou recherche en texte intégral InnoDB de chaque thread a une limite de cache sur les résultats de la requête, qui est définie en octets. Les résultats intermédiaires et finaux des requêtes de recherche en texte intégral InnoDB sont traités en mémoire. Vous pouvez utiliser innodb_ft_result_cache_limit pour définir la limite de taille. La mise en cache des résultats des requêtes de recherche en texte intégral peut éviter une consommation excessive de mémoire lorsque les résultats des requêtes de recherche en texte intégral InnoDB sont très volumineux (par exemple, des millions ou des centaines de millions de lignes). Si la limite de taille du cache des résultats est atteinte, une erreur est renvoyée, indiquant que la requête dépasse la mémoire maximale autorisée.

Solutions recommandées:
Insérez la description de l'image ici
1. Augmentez la valeur de innodb_ft_result_cache_limit pour la rendre supérieure à 4G

SHOW VARIABLES LIKE 'innodb_ft_result_cache_limit%';
set global innodb_ft_result_cache_limit=4000000000;

2. Optimisez l'instruction de requête, limitez le nombre d'enregistrements renvoyés par la requête et réduisez l'énorme cache des résultats intermédiaires. Il est généralement limité par l'affichage de la limite spécifiée.

Problème 2: La vitesse de requête est très instable
En modifiant la valeur de innodb_ft_result_cache_limit, nous avons résolu le problème anormal de la limite du cache.
À ce moment-là, lorsque nous avons essayé de modifier les conditions de la requête, nous avons constaté que les performances de la requête étaient très instables.
Parfois, la vitesse de requête est très rapide, et parfois elle n'est même pas aussi bonne que la requête du module de correspondance complète similaire.
Surtout lorsque la condition de requête est très longue, le problème est très évident et les performances de la requête ne sont pas du tout garanties.

SELECT
	* 
FROM
	wxswj_nsrxx MATCH ( `nsrmc`, `nsrsbh`, `shxydm` ) against ( '中国航天工业科学技术咨询有限公司' IN boolean MODE )

abandonner

Après avoir étudié divers matériaux, je n'ai pas trouvé de meilleure solution et j'ai finalement choisi à contrecœur d'abandonner.

Déclaration de test

create table test(
id int(11) not null primary key auto_increment,
name varchar(100) not null comment '工商名',
brand varchar(100) default null comment '品牌名',
en varchar(100) default null comment '英文名',
fulltext key (name,brand,en) with parser ngram
)engine=innodb default charset=utf8;
insert into test (name,brand,en) values ('芜湖美的厨卫电气制造有限公司','aa','wh');
insert into test (name,brand,en) values ('北京凡客尚品电子商务有限公司','aa','ef');
insert into test (name,brand,en) values ('凡客诚品(北京)科技有限公司','aa','dfd');
insert into test (name,brand,en) values ('瞬联讯通科技(北京)有限公司','aa','sdfs');
insert into test (name,brand,en) values ('北京畅捷通讯有限公司','aa','wsdh');
insert into test (name,brand,en) values ('北京畅捷通支付技术有限公司','aa','df');
insert into test (name,brand,en) values ('畅捷通信息技术股份有限公司','aa','whdfgh');
insert into test (name,brand,en) values ('北京畅捷科技有限公司','aa','dgdf');
insert into test (name,brand,en) values ('中国航天工业科学技术咨询有限公司','aa','whffgh');
insert into test (name,brand,en) values ('北京·松下彩色显象管有限公司','aa','wfghfgh');
insert into test(name,brand,en) select name,brand,en from test;
insert into test(name,brand,en) select name,brand,en from test;
insert into test(name,brand,en) select name,brand,en from test;
insert into test(name,brand,en) select name,brand,en from test;
insert into test(name,brand,en) select name,brand,en from test;
insert into test(name,brand,en) select name,brand,en from test;

EXPLAIN  SELECT  *  from  test  where  match  (name,brand,en)  against  ('通讯录' IN BOOLEAN MODE) LIMIT 100;

La quantité totale de données de test créées est: 655360
sélectionnez le nombre (*) du test;

SELECT  *  from  test  where name like '%美的%' or brand like '%美的%' or en like '%美的%';
耗时:0.544

EXPLAIN  SELECT  *  from  test  where  match  (name,brand,en)  against  ('美的' IN BOOLEAN MODE) LIMIT 100;
耗时:0.150



SELECT  *  from  test  where name like '%芜湖美的厨卫电气制造有限公司%' or brand like '%芜湖美的厨卫电气制造有限公司%' or en like '%芜湖美的厨卫电气制造有限公司%';
耗时:0.679

EXPLAIN  SELECT  *  from  test  where  match  (name,brand,en)  against  ('芜湖美的厨卫电气制造有限公司' IN BOOLEAN MODE) LIMIT 100;
耗时:5.626

En ajoutant des guillemets doubles, la recherche de phrase exacte est réalisée et les conditions de recherche ne correspondent pas à la segmentation des mots. Testons:
Insérez la description de l'image ici

 SELECT  *  from  test  where  match  (name,brand,en)  against  ('"芜湖美的厨卫电气制造有限公司"' IN BOOLEAN MODE) LIMIT 100;
耗时:5.626

Aucun impact sur les performances des requêtes.

Grâce à des expériences, il s'avère que plus la condition de requête est longue, plus les performances de la requête sont lentes.
Vous pouvez le tester et le ressentir vous-même.

Vous êtes invités à partager vos suggestions sur l'utilisation de la recherche en texte intégral mysql.

en conclusion

Cette expérience prouve que MySQL a une prise en charge limitée de la recherche en texte intégral, que la restriction est relativement importante et que les performances des requêtes ne sont pas garanties. Dans de nombreux cas, cela peut ne pas être aussi bon que d'utiliser directement une requête similaire.
Pensez à jouer une petite table avec des centaines de milliers de données.
Lorsqu'une requête floue de correspondance complète est requise pour certaines tables volumineuses, commencez par discuter avec l'entreprise pour savoir si elle peut uniquement prendre en charge la requête floue de pré-correspondance, puis augmentez autant que possible les autres conditions de requête et limitez le nombre d'enregistrements correspondants par limite.
Dans le cadre de requêtes complexes et nécessitant une prise en charge des requêtes floues de correspondance complète et des exigences strictes en matière de performances des requêtes, Elasticsearch est recommandé.

Suivez-moi dans un chat privé et recevez des tutoriels vidéo gratuitement.
Insérez la description de l'image ici
Insérez la description de l'image ici
Plus excitant, suivez-moi.
Légende: Suivez le vieil homme pour apprendre java

Je suppose que tu aimes

Origine blog.csdn.net/w1014074794/article/details/106746114
conseillé
Classement