首页 > 数据库 >mysql中文全文检索从入门到放弃

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

时间:2022-12-07 21:41:12浏览次数:55  
标签:insert en 入门 brand 查询 全文检索 mysql test name


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、查询执行计划

mysql中文全文检索从入门到放弃_数据库


使用了新建的组合全文检索,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全文搜索查询结果非常大(例如,数百万或数亿行)时过多的内存消耗。 如果达到结果缓存大小限制,则返回错误,指示查询超出了最大允许的内存。

推荐解决办法:

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


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

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

mysql中文全文检索从入门到放弃_数据库_03

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

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

通过实验发现,当查询条件越长,查询性能越慢。
大家可以自己测试感受一下。

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

结论

本次实验证明,mysql对全文检索的支持有限,限制比较大,查询性能也得不到保证,很多时候可能比不上直接使用like查询。
几十万数据的小表,可以考虑玩一下。
对一些大表需要全匹配模糊查询时,首先是和业务方商量是否可以只支持前匹配模糊查询,其次尽可能增加其他查询条件,另外通过limit限制匹配的记录数。
复杂查询下,并且一定要求对全匹配模糊查询支持且对查询性能有严格要求,那么推荐使用Elasticsearch。

更多精彩,关注我吧。

mysql中文全文检索从入门到放弃_数据库_04


标签:insert,en,入门,brand,查询,全文检索,mysql,test,name
From: https://blog.51cto.com/u_15905482/5920083

相关文章

  • 一图搞定MySQL体系架构
    要了解mysql的运行机制,那么首先要对mysql的体系结构有一定的了解。最近由于一些事,被打击的不轻,感觉自己可能再怎么努力,职业生涯也就这样了。所以对专研技术、写博客突然丧失......
  • 解析mysql存储结构---innodb_ruby工具
    innodb_ruby用途:主要可查看innodb数据库数据表的各种存储,解析innodb的文件,用于学习数据库底层的一些存储。在debian系统安装innodb_ruby1、sudoaptinstallruby-dev2、su......
  • mysql explain
    explain这个命令来查看SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描等执行explain后,显示的信息有如下几列id:表示查询中执行select子句或操......
  • 爬虫从入门到入狱(五)
    今日内容概要scrapy架构介绍scrapy解析数据settings相关配置持久化方案全站爬取cnblogs文章爬虫和下载中间件今日内容详细scrapy架构介绍#引擎(EGINE)引......
  • mysql数据库导入导出
    1源数据库导出数据 这一步将导出结构和数据到一个.sql文件中2导入到空数据库中将上一步导出的.sql文件传到要服务器某路径下,比如/data/sqldata/devself.sql然后在......
  • FPGA时序入门(新手必看)
    1.FPGA时序的基本概念FPGA器件的需求取决于系统和上下游(upstreamanddownstrem)设备。我们的设计需要和其他的devices进行数据的交互,其他的devices可能是FPGA外部的芯片,可......
  • 绿色版MySQL8.0.26安装流程
    下载 5.7 8.0 官网 https://dev.mysql.com/downloads/mysql/ 国内镜像网站 https://developer.aliyun.com/mirror/ ​ windows安装数据库 安装版: .......
  • 还不会ES?Elasticsearch快速入门实操指南送上
    前言本文主要介绍ES的常用请求,让大家能快速上手ES的使用主要参考官网的​​Quickstart​​指引。一、请求方式向Elasticsearch发送请求主要有2种方式:1、使用restapi发送h......
  • 还不会分布式事务,seata xa模式入门实战送上
    文章目录​​前言​​​​一、什么是seata?​​​​二、seata原理说明​​​​1、角色说明​​​​2、什么是Seata的事务模式?​​​​三、SEATA的分布式案例​​​​1、业......
  • 5分钟,使用yum方式完成mysql安装
    跟着老万,教你5分钟使用yum方式安装mysql。最近打算写一些关于mysql的系列文章,作为第一篇,来教大家如何快速的使用yum命令在线安装mysql。安装的linux环境是7.5,mysql安装的5.7......