当前位置:

首页 > 编程开发 > MySQL全文索引如何优化模糊查询速度问题

MySQL全文索引如何优化模糊查询速度问题

需求需要模糊匹配查询一个单词select*fromt_phrasewhereLOCATE('昌',phrase)=0;select*fromt_chinese_phrasewhereinstr(phrase,'昌')>0;select*fromt_chinese_phrasewherephraselike'%昌%'explain一下看看执行计划由explain的结果可知,虽然我们给phrase建了索引,但是查询的时候,索引是失效的。原因:mysql的索引是B

本文目录

    需求

    需要模糊匹配查询一个单词

    select * from t_phrase where LOCATE('昌',phrase) = 0;

    select * from t_chinese_phrase where instr(phrase,'昌') > 0;

    select * from t_chinese_phrase where phrase like '%昌%'

    explain一下看看执行计划

    MySQL全文索引如何优化模糊查询速度问题

    由explain的结果可知,虽然我们给phrase建了索引,但是查询的时候,索引是失效的。

    原因: mysql的索引是B+树结构,InnoDB在模糊查询数据时使用 "%xx" 会导致索引失效(此处就不展开讲了)

    从查询时长上来看,花费时间:90ms

    目前数据量:93230(9.3W)已经需要90ms,这个时间不太能接受,假如数据量增加,这个时间会不断增长。

    解决方案:

    数据量不大的情况下,使用mysql的全文索引;
    数据量比较大或者mysql的全文索引不达预期的情况下,可以考虑使用ES

    下面主要是MySQL的全文索引相关.

    全文索引介绍

    1、发展历史

    • 旧版的MySQL的全文索引只能用在MyISAM存储引擎的char、varchar和text的字段上。

    • MySQL5.6.24上InnoDB引擎也加入了全文索引。

    2、全文索引

    • 全文检索(Full-Text Search) 是将存储于数据库中的整本书或整篇文章中的任意内容信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、词等信息,也可以进行各种统计和分析

    3、创建全文索引

    若需对大量数据设置全文索引,建议先添加数据再创建索引。

    1、创建表时创建全文索引

    create table 表名(
    字段名1,
    字段名2,
    字段名3,
    字段名4,
    FULLTEXT full_index_name (字段名)
    )ENGINE=InnoDB;

    2、为已有表添加全文索引

    create fulltext index 索引名称 on 表名(字段名);

    eg:

    create table t_word
    (
        id        int unsigned auto_increment comment '自增id' primary key,
        uid       char(32)     not null comment '32位唯一id',
        word      varchar(256) null comment '英文单词',
        translate varchar(256) null
    );
    
    create fulltext index full_idx_translate
        on t_word (translate);
    
    create fulltext index full_idx_word
        on t_word (word);
    
    INSERT INTO t_word (id, uid, word, translate) VALUES (1, '9d592499c65648b0a9519206688ef3f9', 'lion', '狮子');
    INSERT INTO t_word (id, uid, word, translate) VALUES (2, 'ce26ac4239514bc6af481bcb1d9b67df', 'panda', '熊猫');
    INSERT INTO t_word (id, uid, word, translate) VALUES (3, 'a7d6042853c44904b68275daafb44702', 'tiger', '老虎');
    INSERT INTO t_word (id, uid, word, translate) VALUES (4, 'f13bd0a8ecea44fc9ade1625eeb4cc3c', 'goat', '山羊');
    INSERT INTO t_word (id, uid, word, translate) VALUES (5, '27d5cbfc93a046388d712085e567474f', 'sheep', '绵羊');
    INSERT INTO t_word (id, uid, word, translate) VALUES (6, 'ed35df138cf348aa937781be8ee21cbf', 'lamb', '羊羔');
    INSERT INTO t_word (id, uid, word, translate) VALUES (7, 'fba5861d9527440990276e999f47ef8f', 'buffalo', '水牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (8, '3a72e76f210841b1939fff0d3d721375', 'bull', '公牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (9, '272e0b28ea7a48248a86f17533bf9943', 'cow', '母牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (10, '47127adface54e418e4c1b9980af6d16', 'calf', '小牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (11, '10592499c65648b0a9519206688ef3f9', 'little lion', '小狮子');
    INSERT INTO t_word (id, uid, word, translate) VALUES (12, '1bf095110b634a01bee5b31c5ee7ee0c', 'little cow', '母牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (13, '4813e588cde54c30bd65bfdbb243ad1f', 'little calf', '小小牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (14, '5e377e281ad344048b6938a638b78ccb', 'little bull', '小公牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (15, '2855ad0da2964c7682c178eb8271f13d', 'little buffalo', '小水牛');
    INSERT INTO t_word (id, uid, word, translate) VALUES (16, '72f24c9a77644d57a36f3bdf2b8116b0', 'little lamb', '小羊羔');
    INSERT INTO t_word (id, uid, word, translate) VALUES (17, '2d592499c65648b0a9519206688ef3f9', 'I''m a big lion', '我是一只大狮子');

    3、删除全文索引

       alter table 表名 drop index 索引名;

    4、全文索引使用

    语法

    MATCH(col1,col2,...) AGAINST(expr[search_modifier])
    search_modifier:
    {
        IN NATURAL LANGUAGE MODE
        | IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
        | IN BOOLEAN MODE
        | WITH QUERY EXPANSION
    }

    4.1  IN NATURAL LANGUAGE MODE

    自然语言模式是MySQL 默认 的全文检索模式。自然语言模式不能使用操作符,不能指定关键词必须出现或者必须不能出现等复杂查询。

    // 默认是使用 in natural language mode
    select * from t_word where match(word) against ('lion');
    // 或者 显示写
    select * from t_word where match(word) against ('lion' in natural language mode);

    结果如下:

    MySQL全文索引如何优化模糊查询速度问题

    4.2 IN BOOLEAN MODE

    BOOLEAN模式可以使用操作符,可以支持指定关键词必须出现或者必须不能出现或者关键词的权重高还是低等复杂查询。推荐使用boolean模式

    操作者描述
    为空默认,包含该词
    +包括,这个词必须存在。
    -排除,词不得出现。
    >(大于号)包括,并提高排名值,查询的结果会靠前
    <包括,并降低排名值,查询的结果会靠后
    ()将单词分组为子表达式(允许将它们作为一组包括在内,排除在外,排名等等)。
    〜否定单词的排名值。
    *通配符在这个词的结尾。
    “”定义短语(与单个单词列表相对,整个短语匹配以包含或排除)。

    示例:

    // 默认是使用 in natural language mode
    select * from t_word where match(word) against ('lion');
    // 或者 显示写
    select * from t_word where match(word) against ('lion' in natural language mode);

    MySQL全文索引如何优化模糊查询速度问题

    // 排除包含lion记录、查询出包含cow或者little的记录,提升包含calf单词的排名,降低包含cow记录的排名,查询出以go开头的记录
    select * from t_word where match(word) against ('-lion cow little >calf 

    MySQL全文索引如何优化模糊查询速度问题

    好像问题都解决了, 但是问题才刚开始


    回到最开始的需求,我想模糊搜索

    select * from t_word where  match(word) against('lio' in boolean mode);

    预期值:把包含lion的都查询出来 实际结果:啥都没有。

    MySQL全文索引如何优化模糊查询速度问题

    全匹配查询的时候能查询出来

    select * from t_word where  match(translate) against('小水牛' in boolean mode);

    MySQL全文索引如何优化模糊查询速度问题

    只查询部分查询不出来。如:下面只查询 "小水" 或者"水牛" 都没有数据

    select * from t_word where  match(translate) against('小水' in boolean mode);

    MySQL全文索引如何优化模糊查询速度问题

    奇怪了,这咋没出来呢?

    全文索引默认是只按照空格进行分词的,所以当我完整的单个单词去查询的时候是能查出来的。但是使用部分单词去查询或者使用部分中文去查询时,是查询不出来数据的,像中文需要使用中文分词器进行分词。

    中文分词与全文索引

    InnoDB默认的全文索引parser非常合适于Latin,因为Latin是通过空格来分词的。但对于像中文,日文和韩文来说,没有这样的分隔符。一个词可以由多个字来组成,所以我们需要用不同的方式来处理。在MySQL 5.7.6中我们能使用一个新的全文索引插件来处理它们:N-gram parser。

    什么是N-gram?

    在全文索引中,n-gram就是一段文字里面连续的n个字的序列。例如,用n-gram来对“齿轮传动”来进行分词,得到的结果如下:

    N=1 : '齿', '轮', '传', '动';
    N=2 : '齿轮', '轮传', '传动';
    N=3 : '齿轮传', '轮传动';
    N=4 : '齿轮传动';

    这个上面这个N是怎么去配置的?

    查一下目前的值

    show variables like '%token%';

    MySQL全文索引如何优化模糊查询速度问题

    参数解析:

    innodb_ft_min_token_size  
    默认3,表示最小3个字符作为一个关键词,增大该值可减少全文索引的大小  
    innodb_ft_max_token_size
    默认84,表示最大84个字符作为一个关键词,限制该值可减少全文索引的大小
    ngram_token_size
    默认2,表示2个字符作为内置分词解析器的一个关键词,合法取值范围是1-10,如对“abcd”建立全文索引,关键词为’ab’,‘bc’,‘cd’ 当使用ngram分词解析器时,innodb_ft_min_token_size和innodb_ft_max_token_size 无效

    修改方式

    方式1: 在my.cnf中修改/添加参数

    [mysqld]ngram_token_size = 1

    方式2: 修改启动参数

    mysqld --ngram_token_size=1复制代码

    参数均不可动态修改,修改后需重启MySQL服务,并重新建立全文索引

    实际使用

    初始化测试数据

    这里只提供部分测试数据,我下面sql使用全量数据,数据对不上

    create table t_chinese_phrase
    (
        id     int unsigned auto_increment comment 'id'
            primary key,
        phrase varchar(32) not null comment '词组'
    )
        collate = utf8mb4_general_ci;
    
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (278911, '阿昌族');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (279253, '八一南昌起义');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (282316, '昌明');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (282317, '昌盛');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (282318, '昌言');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (286534, '东昌纸');
    INSERT INTO t_chinese_phrase (id, phrase) VALUES (291525, '海昌蓝');
    INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (346682, '繁荣昌盛');
    INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (282317, '昌盛');
    INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (287738, '繁盛');
    INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (287736, '繁荣');

    添加索引

    mysql 全文索引使用倒排索引为 full inverted index
     结构:{单词,(单词所在文档的ID,单词在具体文件中的位置)}

    添加索引:

    alter  table t_chinese_phrase add fulltext ful_phrase (phrase) with parser ngram;

    建完索引,我们可以通过查询INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE和INFORMATION_SCHEMA.INNODB_FT_TABLE_TABLE来查询哪些词在全文索引里面。这是一个非常有用的调试工具。如果我们发现一个包含某个词的文档,没有如我们所期望的那样出现在查询结果中,那么这个词可能是因为某些原因不在全文索引里面。比如,它含有stopword,或者它的大小小于ngram_token_size等等。这个时候我们就可以通过查询这两个表来确认。下面是一个简单的例子:

    # test: 库名  t_chinese_phrase: 表名字
    SET GLOBAL innodb_ft_aux_table="test/t_chinese_phrase";
    # 查询分词情况
    SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
    # 查询分词情况
    select * from information_schema.innodb_ft_index_table;

    查询结果如下:

    MySQL全文索引如何优化模糊查询速度问题

    因为我们上面设置了分词数是1,所以,可以看到都是按照一个词进行分词的。

    字段解析:
    FIRST_DOC_ID :word第一次出现的文档ID
    LAST_DOC_ID : word最后一次出现的文档ID
    DOC_COUNT :含有word的文档个数
    DOC_ID :当前文档ID
    POSITION : word 当在前文档ID的位置

    查询

    1、使用自然语言模式 NATURAL LANGUAGE MODE 查询

    在自然语言模式(NATURAL LANGUAGE MODE)下,文本的查询被转换为n-gram分词查询的并集。

    例如,当ngram_token_size = 1 时,(‘繁荣昌盛’)转换为(‘繁 荣 昌 盛’)。下面一个例子:

    SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST ('繁荣昌盛' in natural language mode) ;

    MySQL全文索引如何优化模糊查询速度问题

    2、使用布尔模式(BOOLEAN MODE)查询

    布尔模式(BOOLEAN MODE)文本查询被转化为n-gram分词的短语查询

    例如,当ngram_token_size = 1 时,(‘繁荣昌盛’)转换为(‘”繁荣昌盛“’)。下面一个例子:

    SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST ('繁荣昌盛' in boolean  mode) ;

    MySQL全文索引如何优化模糊查询速度问题

    实际使用

    回到我们最开始的查询需求,看看实际的效果

    查询包含了“昌”的数据

    SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST ('昌' IN boolean  MODE) ;
    SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST ('昌' ) order by id asc;

    MySQL全文索引如何优化模糊查询速度问题

    可以看到结果:目前“昌”在任意位置都能被查询到。

    查询执行计划如下:

    MySQL全文索引如何优化模糊查询速度问题

    耗时31ms(不走索引是90ms),耗时差不多是之前的1/3。

    注意点

    1、自然语言全文索引创建索引时的字段需与查询的字段保持一致,即MATCH里的字段必须和FULLTEXT里的一模一样;

    2、自然语言检索时,检索的关键字在所有数据中不能超过50%(即常见词),则不会检索出结果。可以通过布尔检索查询;

    3、在mysql的stopword中的单词检索不出结果。可通过

    SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD

    登录后复制

    查询所有的stopword。遇到这种情况,有两种解决办法:

    (1)stopword一般是mysql自建的,但可以通过设置ft_stopword_file变量为自定义文件,从而自己设置stopword,设置完成后需要重新创建索引。但不建议使用这种方法;

    (2)使用布尔索引查询。

    4、小于最短长度和大于最长长度的关键词无法查出结果。可以通过设置对应的变量来改变长度限制,修改后需要重新创建索引。

    myisam引擎下对应的变量名为ft_min_word_len和ft_max_word_len

    innodb引擎下对应的变量名为innodb_ft_min_token_size和innodb_ft_max_token_size

    5、MySQL5.7.6之前的版本不支持中文,需使用第三方插件

    6、全文索引只能在 InnoDB(MySQL 5.6以后) 或 MyISAM 的表上使用,并且只能用于创建 char,varchar,text 类型的列。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 MySQL
    相关文章 更多
    navicat导入数据库步骤详解及常见问题处理教程
    navicat导入数据库步骤详解及常见问题处理教程

    详解Navicat导入数据库的标准步骤,涵盖SQL脚本执行与CSV数据导入两种核心场景。针对导入过程中常见的字符集乱码、主键冲突及外键约束错误,提供具体的设置方法与修复建议,确保数据迁移准确无误。

    SQL主键约束和唯一约束有什么区别
    SQL主键约束和唯一约束有什么区别

    深入理解SQL PRIMARY KEY与UNIQUE约束的区别。文章从行标识与重复限制的目标出发,详解主键的非空特性、外键引用角色以及多数据库对NULL值的处理差异。结合users表实战示例,指导开发者如何根据字段稳定性与业务语义合理选择约束类型,避免设计误区。

    SQL约束有哪些类型及作用
    SQL约束有哪些类型及作用

    刚开始设计关系型数据库?了解PRIMARY KEY、FOREIGN KEY、UNIQUE、NOT NULL、CHECK、DEFAULT等约束的作用、语法和排错方法。本文以PostgreSQL语法为主,结合用户订单场景,清晰展示如何防止脏数据并处理常见约束冲突。

    SQL游标常见错误排查:死锁与资源未释放问题
    SQL游标常见错误排查:死锁与资源未释放问题

    深入解析SQL游标导致的死锁与资源未释放问题。通过PostgreSQL与MySQL语法对比,展示如何识别长事务持锁、分析锁等待链,并提供短事务提交、异常清理及批量处理的最佳实践,确保数据库连接与锁资源及时释放。

    SQL中怎么创建和删除约束
    SQL中怎么创建和删除约束

    后端开发者在维护数据库时,常需对现有表添加主键、唯一或外键约束。若直接执行ADD CONSTRAINT,往往因存量数据不合规导致报错。本文详解操作前的数据清洗步骤、标准SQL语法及MySQL等特殊写法,帮助你在生产环境安全完成结构变更。

    SQL分组统计查询:GROUP BY与HAVING子句用法示例
    SQL分组统计查询:GROUP BY与HAVING子句用法示例

    针对 SQL 初学者的分组统计实战指南。深入解析 GROUP BY 分组机制、WHERE 与 HAVING 的执行时机差异,以及 COUNT 函数对 NULL 值的处理逻辑。通过具体代码示例演示如何正确筛选聚合结果,并排查因 JOIN 连接导致的统计数据异常,提升报表准确性。

    SQL Server与MySQL游标基本语法及完整代码示例
    SQL Server与MySQL游标基本语法及完整代码示例

    本文详细对比SQL Server和MySQL中游标的基本用法。从DECLARE声明到FETCH遍历,再到CLOSE关闭与DEALLOCATE/Handler清理,解析两者在语法结构、变量接收及异常处理上的核心差异。通过标准代码示例展示如何安全使用游标,避免资源泄漏,适用于需要进行数据库存储过程开发或跨平台迁移的开发者。

    SQL多表连接区别:INNER JOIN与LEFT JOIN的使用场景
    SQL多表连接区别:INNER JOIN与LEFT JOIN的使用场景

    深入解析SQL中INNER JOIN与LEFT JOIN的核心区别。通过users和orders表实例,展示匹配行保留与NULL补位机制,重点讲解ON与WHERE子句中放置右表过滤条件的不同后果,提供防止LEFT JOIN退化的实战技巧及行数异常排查步骤。

    SQL模糊匹配查询:LIKE通配符使用规则与注意事项
    SQL模糊匹配查询:LIKE通配符使用规则与注意事项

    详细讲解SQL中LIKE模糊匹配的核心通配符使用规则、转义字符处理、与精确匹配的差异,以及索引失效场景与优化注意事项。

    SQL CHECK约束的用法与取值范围限制
    SQL CHECK约束的用法与取值范围限制

    深入理解 SQL CHECK 约束在 PostgreSQL、MySQL 等数据库中的实现差异。文章通过订单业务场景,讲解如何定义单列范围与多列逻辑约束,分析 NULL 值对布尔条件的影响,并提供修改已有表结构时的安全操作建议,帮助开发者构建更健壮的数据完整性防线。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。