目錄
需求
#全文索引介紹
1、發展歷史
2、全文索引
3、創建全文索引
4、全文索引使用
中文分词与全文索引
什么是N-gram?
这个上面这个N是怎么去配置的?
查一下目前的值
修改方式
实际使用
初始化测试数据
添加索引
查询
1、使用自然语言模式 NATURAL LANGUAGE MODE 查询
2、使用布尔模式(BOOLEAN MODE)查询
注意点
首頁 資料庫 mysql教程 聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

Oct 31, 2022 pm 08:03 PM
mysql

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

模糊查詢,如查詢姓名包含」曉「的用戶,常見的寫法為like "%曉%",MySQL裡面他會全表掃描,資料量少還好,全表掃描也很快,隨著資料增加會變慢,上ES又很重。這篇文章就來跟大家介紹like模糊匹配查詢慢解決之道-MySQL全文索引。

需求

需要模糊匹配查詢一個單字

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全文索引怎麼解決like模糊匹配查詢慢

由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全文索引怎麼解決like模糊匹配查詢慢

4.2 IN BOOLEAN MODE

BOOLEAN模式可以使用操作符,可以支援指定關鍵字必須出現或必須不能出現或關鍵字的權重高還是低等複雜查詢。 推薦使用boolean模式

默認,包含該字#包括,這個字必須存在。 排除,詞不得出現。 包括,並提高排名值,查詢的結果會靠前包括,並降低排名值,查詢的結果會靠後將單字分組為子表達式(允許將它們作為一組包括在內,排除在外,排名等等)。 否定單字的排名值。 通配符在這個字的結尾。
操作者描述
為空
-
>(大於號)
< ;
()
*
######“”######定義短語(與單字清單相對,整個短語匹配以包含或排除)。 ############

示例:

// 默认是使用 in natural language mode
select * from t_word where match(word) against (&#39;lion&#39;);
// 或者 显示写
select * from t_word where match(word) against (&#39;lion&#39; in natural language mode);
登入後複製
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

// 排除包含lion记录、查询出包含cow或者little的记录,提升包含calf单词的排名,降低包含cow记录的排名,查询出以go开头的记录
select * from t_word where match(word) against (&#39;-lion cow little >calf <cow  go*&#39; in boolean mode) ;
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

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


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

select * from t_word where  match(word) against(&#39;lio&#39; in boolean mode);
登入後複製

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

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

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

select * from t_word where  match(translate) against(&#39;小水牛&#39; in boolean mode);
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

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

select * from t_word where  match(translate) against(&#39;小水&#39; in boolean mode);
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

奇怪了,这咋没出来呢?

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

中文分词与全文索引

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

什么是N-gram?

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

N=1 : &#39;齿&#39;, &#39;轮&#39;, &#39;传&#39;, &#39;动&#39;;
N=2 : &#39;齿轮&#39;, &#39;轮传&#39;, &#39;传动&#39;;
N=3 : &#39;齿轮传&#39;, &#39;轮传动&#39;;
N=4 : &#39;齿轮传动&#39;;
登入後複製

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

查一下目前的值

show variables like &#39;%token%&#39;;
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

参数解析:

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 &#39;id&#39;
        primary key,
    phrase varchar(32) not null comment &#39;词组&#39;
)
    collate = utf8mb4_general_ci;

INSERT INTO t_chinese_phrase (id, phrase) VALUES (278911, &#39;阿昌族&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (279253, &#39;八一南昌起义&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (282316, &#39;昌明&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (282317, &#39;昌盛&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (282318, &#39;昌言&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (286534, &#39;东昌纸&#39;);
INSERT INTO t_chinese_phrase (id, phrase) VALUES (291525, &#39;海昌蓝&#39;);
INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (346682, &#39;繁荣昌盛&#39;);
INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (282317, &#39;昌盛&#39;);
INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (287738, &#39;繁盛&#39;);
INSERT INTO test.t_chinese_phrase (id, phrase) VALUES (287736, &#39;繁荣&#39;);
登入後複製

添加索引

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全文索引怎麼解決like模糊匹配查詢慢

因为我们上面设置了分词数是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 (&#39;繁荣昌盛&#39; in natural language mode) ;
登入後複製

聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

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

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

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

SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST (&#39;繁荣昌盛&#39; in boolean  mode) ;
登入後複製

1聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

实际使用

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

查询包含了“昌”的数据

SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST (&#39;昌&#39; IN boolean  MODE) ;
SELECT * FROM t_chinese_phrase WHERE MATCH (phrase) AGAINST (&#39;昌&#39; ) order by id asc;
登入後複製

1聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

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

查询执行计划如下:

1聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢

耗时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 类型的列。

【相关推荐:mysql视频教程

以上是聊聊MySQL全文索引怎麼解決like模糊匹配查詢慢的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

MySQL:世界上最受歡迎的數據庫的簡介 MySQL:世界上最受歡迎的數據庫的簡介 Apr 12, 2025 am 12:18 AM

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

MySQL的位置:數據庫和編程 MySQL的位置:數據庫和編程 Apr 13, 2025 am 12:18 AM

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

apache怎麼連接數據庫 apache怎麼連接數據庫 Apr 13, 2025 pm 01:03 PM

Apache 連接數據庫需要以下步驟:安裝數據庫驅動程序。配置 web.xml 文件以創建連接池。創建 JDBC 數據源,指定連接設置。從 Java 代碼中使用 JDBC API 訪問數據庫,包括獲取連接、創建語句、綁定參數、執行查詢或更新以及處理結果。

為什麼要使用mysql?利益和優勢 為什麼要使用mysql?利益和優勢 Apr 12, 2025 am 12:17 AM

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

docker怎麼啟動mysql docker怎麼啟動mysql Apr 15, 2025 pm 12:09 PM

在 Docker 中啟動 MySQL 的過程包含以下步驟:拉取 MySQL 鏡像創建並啟動容器,設置根用戶密碼並映射端口驗證連接創建數據庫和用戶授予對數據庫的所有權限

MySQL的角色:Web應用程序中的數據庫 MySQL的角色:Web應用程序中的數據庫 Apr 17, 2025 am 12:23 AM

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

laravel入門實例 laravel入門實例 Apr 18, 2025 pm 12:45 PM

Laravel 是一款 PHP 框架,用於輕鬆構建 Web 應用程序。它提供一系列強大的功能,包括:安裝: 使用 Composer 全局安裝 Laravel CLI,並在項目目錄中創建應用程序。路由: 在 routes/web.php 中定義 URL 和處理函數之間的關係。視圖: 在 resources/views 中創建視圖以呈現應用程序的界面。數據庫集成: 提供與 MySQL 等數據庫的開箱即用集成,並使用遷移來創建和修改表。模型和控制器: 模型表示數據庫實體,控制器處理 HTTP 請求。

centos7如何安裝mysql centos7如何安裝mysql Apr 14, 2025 pm 08:30 PM

優雅安裝 MySQL 的關鍵在於添加 MySQL 官方倉庫。具體步驟如下:下載 MySQL 官方 GPG 密鑰,防止釣魚攻擊。添加 MySQL 倉庫文件:rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm更新 yum 倉庫緩存:yum update安裝 MySQL:yum install mysql-server啟動 MySQL 服務:systemctl start mysqld設置開機自啟動

See all articles