现在我们数据库表中的记录大约在17万,每一条记录都有name字段,根据name做模糊匹配,效率非常低下。

表结构如下:

create table T
(
id int,
name varchar(64)
);

总数据量如下:

mysql> select count(*) from T;
+----------+
| count(*) |
+----------+
| 175152 |
+----------+
1 row in set (0.00 sec)

按照名称进行模糊匹配执行结果如下,用时0.29秒:

mysql> select count(*) from T where (name like '%玻璃奶瓶%');
+----------+
| count(*) |
+----------+
| 712 |
+----------+
1 row in set (0.29 sec)
mysql> select  id, name from T where (name like '%玻璃奶瓶%') limit 0,10;
+---------+---------------------------------------------------------------+
| id | name |
+---------+---------------------------------------------------------------+
| 1206852 | 伊诗比蒂-120ML标准口径玻璃奶瓶防摔护套BT-1250 |
| 1206853 | 伊诗比蒂-120ML宽口径玻璃奶瓶防摔护套BT-1251 |
| 1206854 | 伊诗比蒂-200ML标准口径玻璃奶瓶防摔护套BT-1252 |
| 1206855 | 伊诗比蒂-160ML宽口径玻璃奶瓶防摔护套BT-1253 |
| 1206856 | 伊诗比蒂-240ML标准口径玻璃奶瓶防摔护套 |
| 1206857 | 240ML宽口径玻璃奶瓶防摔护套BT-1255 |
| 1309742 | 贝亲标准口径玻璃奶瓶240ml |
| 1309743 | 贝亲标准口径玻璃奶瓶200ml |
| 1309744 | 贝亲标准母乳实感奶嘴玻璃奶瓶120ml |
| 1309745 | 贝亲硅胶宽口径玻璃奶瓶240ml |
+---------+---------------------------------------------------------------+
10 rows in set (0.19 sec)

like操作无法走到索引,正好趁着机会尝试下MySql的全文索引功能。

因为中文语句不像英文,单词与单词之间用空格隔开,存在天然的分隔符,因此当前MySql的全文索引无法支持中文。

当然,也有办法可以绕过去,比如把汉字进行转码或者转成拼音,经过比较,最终还是确定使用转base64的方法,只针对中文做转换,英文和和符号不转。

首先,需要修改表结构,增加一个字段用来保存转码后的值,并创建这个字段的全文索引

alter table T add column nameindex varchar(256) not null default '';
alter table T add fulltext name_index_fc(`nameindex `);

然后,通过脚本批量刷新数据,把每条记录中的name转码后存入nameindex。空格是mysql全文索引的分词符之一,为了能实现和like匹配一样的功能,需要以字为最小单位,字与字之间的base64编码用空格分开。

下面是python的转码实现:

d='伊诗比蒂-160ML宽口径玻璃奶瓶防摔护套BT-1253'
baseStr = ''
for i in range(len(d)):
#print base64.encodestring(d[i].encode('utf8')).strip('\n\r')
#if re.match('[ \u4e00 -\u9fa5]+',d[i]) == None:
if d[i] >= u'\u4e00' and d[i]<=u'\u9fa5':
b = ''
if len(baseStr) != 0:
b = ' '
b += base64.encodestring(d[i].encode('utf8')).strip('\n\r')
baseStr += b
baseStr += ' '
else:
dt = d[i]
if d[i] == '"' or d[i] == "'":
dt = '\\'
dt += d[i]
baseStr += dt
baseStr += ' '

转换完成后,结果如下:

mysql> select  id,name,nameindex from T where (name like '%玻璃奶瓶%') limit 0,10;
+---------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
| id | name | nameindex |
+---------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
| 1206852 | 伊诗比蒂-120ML标准口径玻璃奶瓶防摔护套BT-1250 | 5LyK 6K+X 5q+U 6JKC -120ML 5qCH 5YeG 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX BT-1250 |
| 1206853 | 伊诗比蒂-120ML宽口径玻璃奶瓶防摔护套BT-1251 | 5LyK 6K+X 5q+U 6JKC -120ML 5a69 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX BT-1251 |
| 1206854 | 伊诗比蒂-200ML标准口径玻璃奶瓶防摔护套BT-1252 | 5LyK 6K+X 5q+U 6JKC -200ML 5qCH 5YeG 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX BT-1252 |
| 1206855 | 伊诗比蒂-160ML宽口径玻璃奶瓶防摔护套BT-1253 | 5LyK 6K+X 5q+U 6JKC -160ML 5a69 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX BT-1253 |
| 1206856 | 伊诗比蒂-240ML标准口径玻璃奶瓶防摔护套 | 5LyK 6K+X 5q+U 6JKC -240ML 5qCH 5YeG 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX |
| 1206857 | 240ML宽口径玻璃奶瓶防摔护套BT-1255 | 240ML 5a69 5Y+j 5b6E 5467 55KD 5aW2 55O2 6Ziy 5pGU 5oqk 5aWX BT-1255 |
| 1309742 | 贝亲标准口径玻璃奶瓶240ml | 6LSd 5Lqy 5qCH 5YeG 5Y+j 5b6E 5467 55KD 5aW2 55O2 240ml |
| 1309743 | 贝亲标准口径玻璃奶瓶200ml | 6LSd 5Lqy 5qCH 5YeG 5Y+j 5b6E 5467 55KD 5aW2 55O2 200ml |
| 1309744 | 贝亲标准母乳实感奶嘴玻璃奶瓶120ml | 6LSd 5Lqy 5qCH 5YeG 5q+N 5Lmz 5a6e 5oSf 5aW2 5Zi0 5467 55KD 5aW2 55O2 120ml |
| 1309745 | 贝亲硅胶宽口径玻璃奶瓶240ml | 6LSd 5Lqy 56GF 6IO2 5a69 5Y+j 5b6E 5467 55KD 5aW2 55O2 240ml |
+---------+---------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------+
10 rows in set (0.21 sec)

测试一下性能,耗时0.05秒,提升了四倍的速度

mysql> SELECT count(*) FROM T WHERE MATCH (nameindex AGAINST ('"5467 55KD 5aW2 55O2"' IN BOOLEAN MODE) ;
+----------+
| count(*) |
+----------+
| 713 |
+----------+
1 row in set (0.05 sec)

再多试几次,性能都有很大的提升

mysql> select count(*) from T where (nameindex like '%凌动%');
+----------+
| count(*) |
+----------+
| 70 |
+----------+
1 row in set (0.30 sec) mysql> SELECT count(*) FROM T WHERE MATCH (nameindex) AGAINST ('"5YeM 5Yqo"' IN BOOLEAN MODE) ;
+----------+
| count(*) |
+----------+
| 70 |
+----------+
1 row in set (0.01 sec) mysql> select count(*) from T where (nameindex like '%凌动惯性%');
+----------+
| count(*) |
+----------+
| 9 |
+----------+
1 row in set (0.29 sec) mysql> SELECT count(*) FROM T WHERE MATCH (nameindex) AGAINST ('"5YeM 5Yqo 5oOv 5oCn"' IN BOOLEAN MODE) ;
+----------+
| count(*) |
+----------+
| 9 |
+----------+
1 row in set (0.00 sec)

细心的你,可能发现了查找‘玻璃奶瓶’的时候,用like和全文索引查找出来的记录总数相差1。

相差的这条记录如下:

mysql> select  id ,name,nameindex from T where id = 1314118;
+---------+-----------------------------------------------+------------------------------------------------------------------------------+
| id | name | nameindex |
+---------+-----------------------------------------------+------------------------------------------------------------------------------+
| 1314118 | NUK宽口-玻璃-奶瓶妈咪礼包40.260.718 | NUK 5a69 5Y+j - 5467 55KD - 5aW2 55O2 5aaI 5ZKq 56S8 5YyF 40.260.718 |
+---------+-----------------------------------------------+------------------------------------------------------------------------------+

在玻璃和奶瓶之间有一个“-”,因为“-”前后都是汉字,因此转码操作了,“-”成为了一个独立的字符。根据MySql全文索引的默认配置ft_min_word_len = 4,低于4个字符的词不会被保存在索引中。因此“-”被忽略。

【mysql】利用全文索引实现中文的快速查找的更多相关文章

  1. mysql利用binlog进行数据恢复

    目录 mysql利用binlog进行数据恢复 binlog基本配置和格式 binlog基本配置 查看binlog状态 binlog的三种格式 转换成sql mysql自带的mysqlbinlog 利用 ...

  2. (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例)

    (私人收藏)[开发必备]最全Java离线快速查找手册(可查询可学习,带实例) https://pan.baidu.com/s/1L54VuFwCdKVnQGVc8vD1TQnwmj java手册 Ja ...

  3. PHP实现文本快速查找 - 二分查找

    PHP实现文本快速查找 - 二分查找法 起因 先说说事情的起因,最近在分析数据时经常遇到一种场景,代码需要频繁的读某一张数据库的表,比如根据地区ID获取地区名称.根据网站分类ID获取分类名称.根据关键 ...

  4. <转>java 快速查找

    [Ct rl+T] 搜索当前接口的实现类 1. [ALT +/]    此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ ...

  5. 【NYOJ-187】快速查找素数—— 枚举法、筛选法、打表法

    快速查找素数 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 现在给你一个正整数N,要你快速的找出在2.....N这些数里面所有的素数. 输入 给出一个正整数数N(N ...

  6. 快速排序/快速查找(第k个, 前k个问题)

    //快速排序:Partition分割函数,三数中值分割 bool g_bInvalidInput = false; int median3(int* data, int start, int end) ...

  7. MySQL复制异常大扫盲:快速溯源与排查错误全解

    MySQL复制异常大扫盲:快速溯源与排查错误全解https://mp.weixin.qq.com/s/0Ic8BnUokyOj7m1YOrk1tA 作者介绍王松磊,现任职于UCloud,从事MySQL ...

  8. Mysql 利用拷贝data目录文件的方式迁移mysql数据库

    Mysql 利用拷贝data目录文件的方式迁移mysql数据库 步骤如下: 1.首先要确定data目录 这个问题困扰了我很久,因为网上的帖子大部分只是说拷贝mysql数据库目录下的data文件夹中的数 ...

  9. MySql 利用crontab实现MySql定时任务

    MySql 利用crontab实现MySql定时任务 by:授客 QQ:1033553122 适用平台 任意myslq版本数据库 操作方法 登陆到数据库系统所在的linxu系统 第一步:新建名为cro ...

随机推荐

  1. java 接口default的判断规则

    1.前言 jdk1.8中新增加了default关键字,就是在接口中可以增加默认实现. 因为改动接口所有的实现类都要改动,所以增加了default关键字后不需要修改其他类,默认给所有实现类增加了方法. ...

  2. #Java学习之路——基础阶段二(第十三篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  3. Java基础/Java异常

    Java异常 1.异常的分类: ① 非运行时异常(Checked Exception) Java中凡是继承自Exception但不是继承自RuntimeException的类都是非运行时异常 ② 运行 ...

  4. Java学习开发第一阶段总结

    前言: 按照学院的安排我专业应该在下学期学习Java课程,因为对技术的热爱,我选择了在本学期学习Java.俗话说得好“笨鸟先飞”,那我就先学习这门课程了. 第一阶段的学习总结: 在此次阶段任务相对比较 ...

  5. C# 字符串、字节数组互相转换

    /// <summary> /// MD5加密 /// </summary> /// <param name="sender"></par ...

  6. C++中多态的概念和意义

    1,函数重写回顾: 1,父类中被重写的函数依然会继承给子类: 2,子类中重写的函数将覆盖父类中的函数: 1,重写父类当中提供的函数是因为父类当中提供的这个函数版本不能满足我们的需求,因此我们要重写: ...

  7. python-event事件-模仿红绿灯

    import time import threading event =threading.Event() def lighter(): count=0 event.set()#先设置成绿灯 whil ...

  8. 机器学习-SVM中的SMO算法详解

  9. EasyTest-接口自动化测试平台部署上线问题记录

    平台url:   http://easytest.xyz 花巨资搞了个阿里云服务器,哈哈,有想体验指导的大佬私聊我~~~ 部署环境 云服务器:Ubuntu Server 16.04.1 LTS 64位 ...

  10. Win7 MongoDB可视化工具Robo 3T 1.2.1(robomongo)的安装使用

    软件版本: Robo 3T 1.2.1 下载网址: https://robomongo.org/campaign 进入robomongo官网,点击download,进入下载页面 这里选择下载 Robo ...