mysql中文全文检索从入门到放弃

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: like全匹配模糊查询不能使用索引一直是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 indexes are created on text-based columns (CHAR, VARCHAR, or TEXT columns)

全文索引只能被创建在CHAR, VARCHAR, or TEXT的字段上。

每张表只能有一个全文检索的索引

由多列组合而成的全文检索的索引必须使用相同的字符集与排序规则


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 )


这里使用东鹏去模糊匹配nsrmc, nsrsbh, shxydm这三个字段,任意一个字段中包含查询关键字东鹏就返回对应记录。


8、查询执行计划

6.png

使用了新建的组合全文检索,ref达到const级别


9、优化效果

查询性能提升了100多倍。



目前为止,好像一切都非常美好,但很快坑就出现了。

当查询的关键词太长,就出现了异常?


问题一:FTS query exceeds result cache limit

当采用比较长的查询条件去匹配执行查询或甚至执行查询计划时,出现异常:


188 - FTS query exceeds result cache limit


mysql官网中对该异常的解释说明:

https://bugs.mysql.com/bug.php?id=86036


每个全文搜索查询或每个线程的InnoDB全文搜索都对查询结果进行了缓存限制,以字节为单位定义。中间和最终的InnoDB全文搜索查询结果在内存中处理。可以使用innodb_ft_result_cache_limit设置大小限制。全文搜索查询结果缓存可避免InnoDB全文搜索查询结果非常大(例如,数百万或数亿行)时过多的内存消耗。 如果达到结果缓存大小限制,则返回错误,指示查询超出了最大允许的内存。


推荐解决办法:

7.png

1、增加innodb_ft_result_cache_limit的值,使其大于4G


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


2、优化查询语句,限制查询返回的记录条数,减少来自中间结果的巨大缓存。一般通过显示指定limit来限制。


问题二:查询速度非常不稳定

我们通过修改innodb_ft_result_cache_limit的值,解决了缓存限制的异常问题。

当时,我们尝试修改查询条件时,发现查询性能非常不稳定。

有时候查询速度非常快,有时候甚至比不上like全匹配模块查询。

特别是当查询条件非常长的时候,问题非常明显,查询性能完全没有保证。

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 count(*) from 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


通过加双引号,实现确切短语搜索,不对搜索条件进行分词匹配,我们测试下:

8.png


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


发现对查询性能没有影响。


通过实验发现,当查询条件越长,查询性能越慢。

大家可以自己测试感受一下。


有关于mysql全文检索使用好的建议,欢迎分享。


结论


本次实验证明,mysql对全文检索的支持有限,限制比较大,查询性能也得不到保证,很多时候可能比不上直接使用like查询。


几十万数据的小表,可以考虑玩一下。


对一些大表需要全匹配模糊查询时,首先是和业务方商量是否可以只支持前匹配模糊查询,其次尽可能增加其他查询条件,另外通过limit限制匹配的记录数。


复杂查询下,并且一定要求对全匹配模糊查询支持且对查询性能有严格要求,那么推荐使用Elasticsearch。


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
19天前
|
存储 监控 关系型数据库
轻松入门Mysql:MySQL性能优化与监控,解锁进销存系统的潜力(23)
轻松入门Mysql:MySQL性能优化与监控,解锁进销存系统的潜力(23)
|
19天前
|
SQL 数据可视化 关系型数据库
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
轻松入门MySQL:深入探究MySQL的ER模型,数据库设计的利器与挑战(22)
103 0
|
19天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
轻松入门MySQL:数据库设计之范式规范,优化企业管理系统效率(21)
|
19天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:揭秘MySQL游标,数据处理的神秘利器(16)
轻松入门MySQL:揭秘MySQL游标,数据处理的神秘利器(16)
|
19天前
|
存储 SQL 关系型数据库
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
轻松入门MySQL:加速进销存!利用MySQL存储过程轻松优化每日销售统计(15)
|
19天前
|
SQL 关系型数据库 MySQL
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
轻松入门MySQL:保障数据完整性,MySQL事务在进销存管理系统中的应用(12)
|
19天前
|
存储 关系型数据库 MySQL
轻松入门MySQL:优化进销存管理,掌握MySQL索引,提升系统效率(11)
轻松入门MySQL:优化进销存管理,掌握MySQL索引,提升系统效率(11)
|
19天前
|
关系型数据库 MySQL 数据库
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
轻松入门MySQL:精准查询,巧用WHERE与HAVING,数据库查询如虎添翼(7)
|
19天前
|
SQL 存储 关系型数据库
轻松入门MySQL:玩转数据表的增、删、改、查(4)
轻松入门MySQL:玩转数据表的增、删、改、查(4)
|
2月前
|
SQL 存储 关系型数据库
解析MySQL Binlog:从零开始的入门指南【binlog入门指南】
解析MySQL Binlog:从零开始的入门指南【binlog入门指南】
1032 0