MySQLエントリから破棄までの全文検索

完全一致ファジークエリがインデックスを使用できないのと同じように、常にsqlクエリの厄介な問題なので、mysqlの全文検索で本当にこの問題を解決できますか?

バックグラウンド

最近、作業中にクエリの最適化の問題が発生しました。簡略化したSQLは次のとおりです。

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

質問:
1.完全一致ファジークエリが使用されている
2. ORキーワードが使用されている

明らかに、このようなクエリにはインデックスを付けることができません。また、テーブルのデータ量は非常に大きく、500万以上のデータがあるため、クエリ全体の応答速度は非常に不十分です。

実際の中国語全文検索

ngramセグメンテーション挿入の手順:
https ://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html リンクの説明を追加

1.最適化のアイデア:
中国のあいまい一致クエリには、主に単語のセグメンテーションと全文検索が含まれ、mysqlには全文索引FULLTEXTの索引タイプがあります。ですから、フルテキストインデックスを使用して、mysqlの完全一致ファジークエリの問題を解決したいと思います。

2.説明:
MySQL 5.7.6より前のフルテキストインデックスは、英語のフルテキストインデックスのみをサポートしており、中国語のフルテキストインデックスはサポートしていません。中国語の段落を単語に前処理してデータベースに保存するには、単語セグメンターを使用する必要があります。
MySQL 5.7.6以降、MySQLには中国語の単語分割をサポートする組み込みのngramフルテキストパーサーがあります。

3.現在のデータベースバージョンを表示します。

select version() from dual;

結果は5.7.28で、中国語の全文検索をサポートしています

4.フルテキスト検索の制限:
FULLTEXTインデックスはテキストベースの列(CHAR、VARCHAR、またはTEXTカラム)
に作成されますフルテキストインデックスは、CHAR、VARCHAR、またはTEXTカラムにのみ作成できます。
各テーブルには1つの全文検索インデックスのみを含めることができます
。複数の列で構成される全文検索インデックスは、同じ文字セットと照合順序を使用する必要があります。

5.クエリキャッシュの
sql最適化を閉じる前に、クエリキャッシュは通常閉じられています:
SHOW VARIABLES LIKE'query_cache% ';
set global query_cache_size = 0;
set global query_cache_type = 0;

SHOW VARIABLES LIKE 'query_cache%';

6.フルテキストインデックスを作成する

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

7.フルテキストインデックスを使用
する** MATCH(col1、col2、...)AGAINST(expr [search_modifier])**ステートメントでフルテキストインデックスを使用します

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

ここ东鹏、ファジーマッチングの3つのフィールドが使用されnsrmcいずれかのフィールドにクエリキーが含まれている場合nsrsbh対応するレコードが返さshxydmれます东鹏

8.クエリ実行プラン
ここに画像の説明を挿入
は新しく結合された全文検索を使用し、refはconstレベルに達します

9.最適化効果
クエリのパフォーマンスが100倍以上向上しました。

ピット

これまでのところ、すべてが非常に良いようですが、すぐにピットが現れました。
クエリキーワードが長すぎると、例外が発生しますか?

質問1:
比較的長いクエリ条件を使用してクエリを照合したり、クエリプランを実行したりすると、FTSクエリが結果キャッシュの制限を超え、例外が発生します。

188 - FTS query exceeds result cache limit

mysql公式Webサイトの例外の説明:https :
//bugs.mysql.com/bug.php?id=86036

各スレッドの全文検索クエリまたはInnoDB全文検索には、クエリ結果に対するキャッシュ制限があり、バイト単位で定義されます。中間および最終のInnoDB全文検索クエリ結果はメモリで処理されます。innodb_ft_result_cache_limitを使用してサイズ制限を設定できます。フルテキスト検索クエリ結果のキャッシュにより、InnoDBフルテキスト検索クエリ結果が非常に大きい場合(たとえば、数百万または数億行)、過度のメモリ消費を回避できます。結果のキャッシュサイズの制限に達すると、エラーが返され、クエリが最大許容メモリを超えたことを示します。

推奨される解決策:
ここに画像の説明を挿入
1. innodb_ft_result_cache_limitの値を増やして、4Gより大きくします。

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

2.クエリステートメントを最適化し、クエリによって返されるレコードの数を制限し、中間結果からの巨大なキャッシュを減らします。通常、指定された制限を表示することで制限されます。

問題2:クエリ速度が非常に不安定
であるinnodb_ft_result_cache_limitの値を変更することで、キャッシュ制限の異常な問題を解決しました。
当時、クエリの条件を変更しようとすると、クエリのパフォーマンスが非常に不安定であることがわかりました。
クエリの速度は非常に速い場合もあれば、完全一致モジュールのクエリほどよくない場合もあります。
特にクエリ条件が非常に長い場合、問題は非常に明白であり、クエリのパフォーマンスはまったく保証されません。

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

あきらめる

いろいろな資料を調べた結果、もっと良い解決策が見つからず、やっとあきらめて諦めました。

テストステートメント

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;

作成されるテストデータの合計量は次のとおりです。655360
テストから選択カウント(*)。

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

二重引用符を追加することにより、完全なフレーズ検索が実現され、検索条件が単語のセグメンテーションと一致しなくなります。テストしてみましょう。
ここに画像の説明を挿入

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

クエリのパフォーマンスへの影響はありません。

実験により、クエリ条件が長くなるほど、クエリのパフォーマンスが低下することがわかっています。
自分でテストして感じることができます。

mysqlの全文検索の使用に関する提案を共有していただけます。

結論として

この実験は、MySQLの全文検索のサポートが制限されており、制限が比較的大きく、クエリのパフォーマンスが保証されていないことを証明しています。多くの場合、同様のクエリを直接使用するほど良くない場合があります。
数十万のデータを含む小さなテーブルを再生することを検討してください。
一部の大きなテーブルで完全一致ファジークエリが必要な場合は、まずビジネス側と事前一致ファジークエリしかサポートできないかどうかを話し合い、次に他のクエリ条件を可能な限り増やし、一致するレコードの数を制限で制限します。
複雑なクエリでは、完全一致のファジークエリサポートとクエリパフォーマンスに関する厳しい要件が必要な場合は、Elasticsearchをお勧めします。

プライベートチャットでフォローして、ビデオチュートリアルを無料で受け取ってください。
ここに画像の説明を挿入
ここに画像の説明を挿入
もっとわくわくしてください。
凡例:老人をフォローしてJavaを学ぶ

おすすめ

転載: blog.csdn.net/w1014074794/article/details/106746114
おすすめ