用户表有个昵称字段需要模糊搜索 而且搜索量巨大 而且必须支持特殊字符串
个人不喜欢架构复杂化 多用elasticsearch、solr、sphinx 很麻烦
所以研究了个通用解决方案 mysql支持索引模糊搜索
1.首先修改mysql配置 改成全文索引最小为1字符串
sql
[mysqld]
innodb_ft_min_token_size=1
ft_min_word_len=1
2.新建STORED 虚拟字段 nickname_index 绑定原始nickname字段变化跟着一起变
3.nickname_index 创建全文索引
sql
CREATE TABLE `tb_user` (
`uid` int unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '别名',
`nickname_index` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin GENERATED ALWAYS AS (regexp_replace(`nickname`,_utf8mb4'(.)',_utf8mb4'$1 ')) STORED COMMENT '全文索引',
PRIMARY KEY (`uid`) USING BTREE,
FULLTEXT KEY `nickname_index` (`nickname_index`)
) ENGINE=InnoDB AUTO_INCREMENT=1001371 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='用户表';
4.客户端写SQL注意事项 需要用同样的方案
sql
desc
SELECT
*
from tb_user
where
MATCH(nickname_index) AGAINST( regexp_replace('关键字','(.)','$1 ') )
and
nickname like CONCAT('%','关键字','%')
成功使用索引了
实现方案是
1.用虚拟键绑定原始键(原始值变了 索引也会跟着自动变)
2.利用全文索引 (把虚拟键字符串逐字插入空格 强制用1字符串分词)
sql
regexp_replace('关键字','(.)','$1 ')
3.使用时先用全文索引 搜索分好词的关键字 再like一下原始键 数据就准确了
sql
where
MATCH(nickname_index) AGAINST( regexp_replace('关键字','(.)','$1 ') )
and
nickname like CONCAT('%','关键字','%')
PS: 低版本mysql 没有regexp_replace 需要用编程语言先处理好再传进来 也可以支持 麻烦点
作者:LingMax 原创mysql支持索引模糊搜索 喜欢点个赞