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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 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。


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
5月前
|
安全 关系型数据库 MySQL
PHP与MySQL交互:从入门到实践
【9月更文挑战第20天】在数字时代的浪潮中,掌握PHP与MySQL的互动成为了开发动态网站和应用程序的关键。本文将通过简明的语言和实例,引导你理解PHP如何与MySQL数据库进行对话,开启你的编程之旅。我们将从连接数据库开始,逐步深入到执行查询、处理结果,以及应对常见的挑战。无论你是初学者还是希望提升技能的开发者,这篇文章都将为你提供实用的知识和技巧。让我们一起探索PHP与MySQL交互的世界,解锁数据的力量!
|
9月前
|
存储 监控 关系型数据库
轻松入门Mysql:MySQL性能优化与监控,解锁进销存系统的潜力(23)
轻松入门Mysql:MySQL性能优化与监控,解锁进销存系统的潜力(23)
152 0
|
1月前
|
SQL 关系型数据库 MySQL
网安入门之MySQL后端基础
《网安入门之MySQL后端基础》简介: 本文介绍了数据库及MySQL的基础知识,涵盖数据库的概念、结构与操作。数据库是组织化存储数据的集合,通过表、列、行等结构实现高效管理。MySQL作为开源的关系型数据库管理系统,广泛应用于Web开发。文中详细讲解了MySQL的基本操作,如增(INSERT)、删(DELETE)、改(UPDATE)、查(SELECT)等语句的使用方法,并介绍了数据库事务的ACID特性。此外,还探讨了SQL注入攻击的风险及防范措施,强调了预处理语句的重要性。最后,简述了PHP中mysqli扩展的使用方法,包括连接数据库、执行查询和关闭连接等步骤。
|
5月前
|
关系型数据库 MySQL 数据库
MySQL基本操作入门指南
MySQL基本操作入门指南
229 0
|
9月前
|
存储 关系型数据库 MySQL
MySQL基础入门:数据库操作全攻略
MySQL基础入门:数据库操作全攻略
213 0
|
5月前
|
SQL 关系型数据库 MySQL
MySQL入门到精通
MySQL入门到精通
|
7月前
|
SQL 关系型数据库 MySQL
「Python入门」python操作MySQL和SqlServer
**摘要:** 了解如何使用Python的pymysql模块与MySQL数据库交互。首先,通过`pip install pymysql`安装模块。pymysql提供与MySQL的连接功能,例如创建数据库连接、执行SQL查询。在设置好MySQL环境后,使用`pymysql.connect()`建立连接,并通过游标执行SQL(如用户登录验证)。注意防止SQL注入,使用参数化查询。增删改操作需调用`conn.commit()`来保存更改。pymssql模块类似,但导入和连接对象创建略有不同。
88 0
「Python入门」python操作MySQL和SqlServer
|
7月前
|
SQL 关系型数据库 MySQL
【MySQL从入门到精通】常用SQL语句分享
【MySQL从入门到精通】常用SQL语句分享
90 2
|
8月前
|
关系型数据库 MySQL 数据库
『Django』模型入门教程-操作MySQL
一个后台如果没有数据库可以说废了一半。日常开发中大多数时候都在与数据库打交道。Django 为我们提供了一种更简单的操作数据库的方式。 在 Django 中,模型(Model)是用来定义数据库结构的类。每个模型类通常对应数据库中的一个表,类的属性对应表中的列。通过定义模型,Django 的 ORM(Object-Relational Mapping)可以将 Python 对象映射到数据库表,并提供一套 API 来进行数据库操作。 本文介绍模型的用法。
|
8月前
|
Java 关系型数据库 MySQL
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
72 4