当前位置:网站首页>MySQL 45 讲 | 11 怎么给字符串字段加索引?
MySQL 45 讲 | 11 怎么给字符串字段加索引?
2022-08-04 10:48:00 【蓝布棉】
11 | 怎么给字符串字段加索引?
如何在邮箱这样的字段上建立合理的索引 ?
第一个语句创建的index1索引里面,包含了每个记录的整个字符串;
第二个语句创建的index2 索引里面,对于每个记录都是只取前6个字节
mysql> alter table SUser add index index1(email); mysql> alter table SUser add index index2(email(6));- index 1 使用email全部字段创建索引,查找时回全表扫描。
- index 2 使用email的前6个字段创建前缀索引, 占用的空间更小,但会增加额外的记录扫描次数 。
这两个索引定义下分别执行下面查询语句:
select id,name,email from SUser where email='[email protected]';- 使用的是index1(即email整个字符串的索引结构),执行顺序是这样的:
- 从index1索引树找到满足索引值是’[email protected]’的这条记录,取得ID2的值;
- 到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;
- 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足 email='[email protected]’的条件了,循环结束。
- 如果使用的是index2(即email(6)索引结构),执行顺序是这样的:
- 从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;
- 到主键上查到主键值是ID1的行,判断出email的值不是’[email protected]’,这行记录丢弃;
- 取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;
- 重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。
使用前缀索引,定义好长度,就可以既节省空间,又不用额外增加太多的查询成本。
怎样确定应该使用多长的前缀呢?
区分度,区分度越高越好
- 可以使用下面这个语句,算出这个列上有多少个不同的值
mysql> select
count(distinct left(email,4))as L4,
count(distinct left(email,5))as L5,
count(distinct left(email,6))as L6,
count(distinct left(email,7))as L7,
from SUser;
依次选取不同长度的前缀,使用前缀索引很可能会损失区分度,所以需要预先设定一个可以接受的损失比例,比如 5%。然后,在返回的L4~L7中,找出不小于 L * 95%的值,假设这里L6、L7都满足,你就可以选择前缀长度为6。
前缀索引对覆盖索引的影响
下面两个SQL语句:
select id,email from SUser where email='[email protected]';
select id,name,email from SUser where email='[email protected]';
- 第一个语句只要求返回id和email字段。
- 如果使用index1(即email整个字符串的索引结构)的话,可以利用覆盖索引,从index1查 到结果后直接就返回了,不需要回到ID索引再去查一次。
- 如果使用index2(即email(6)索引结构)的话,不得不回到ID索引再去判断email字段的值 。
使用前缀索引就用不上覆盖索引对查询性能的优化了。
前缀的区分度不够好的情况时,怎么办呢?
比如,我们国家的身份证号,一共18位,其中前6位是地址码,所以同一个县的人的身份证号前 6位一般会是相同的。还有没有别的处理 方法呢?这种方法,既可以占用更小的空间,也能达到相同的查询效率。
- 倒序存储 : 存储身份证号候把它倒过来存,每次查询的时候,可以这么写:
select field_list from t where id_card = reverse('input_id_card_string');
使用 reverse() 函数把数字倒过来,可以用最后6位的区分度创建前缀索引,使用count(distinct)方法去做个验证 。
- hash字段:在表上再创建一个整数字段,来保存身份证的校验码, 同时在这个字段上创建索引。
alter table t add id_card_crc int unsigned, add index(id_card_crc);
select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
用crc32()这个函数得到校验码填到这个新字段。
倒序存储和使用hash字段的异同点 :
相同点: 都不支持范围查询。 倒序存储不支持范围查询;hash字段也只能支持等值查询。
不同点:
- 额外空间: 倒序存储方式在主键索引上,不会消耗额外的存储空间;而hash字段方法需要增加一个字段。
- CPU消耗: 倒序方式每次写和读时,都需要额外调用一次reverse函数;而hash 字段的方式需要额外调用一次crc32()函数。reverse函数额外消耗的CPU资源会更小些 。
- 查询效率 : hash字段方式的查询性能相对更稳定一些,可以认为每次查询的平均扫描行数接近1 ;倒序存储 方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。
小结
字符串字段创建索引的场景
- 创建完整索引,比较占用空间
- 创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引
- 倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题,不支持范围扫描
- hash字段索引,查询性能稳定,有额外的存储和计算消耗,不支持范围扫描
边栏推荐
- 华为开源:聚焦开源基础软件,共建健康繁荣生态
- Digital management insight into retail and e-commerce operations - retail password
- safe-point(safepoint 安全点) 和 safe-region(安全区域)「建议收藏」
- Multimedia and Internet of Things technology make the version "live" 129 vinyl records "Centennial Voice"
- HCIP 交换实验
- 再次搞定 Ali 云函数计算 FC
- 北京大学,新迎3位副校长!其中一人为中科院院士!
- HCIP 第十七天
- 栈与队列的实现
- 章节小测一
猜你喜欢
随机推荐
自己实现一个枚举validation校验器
[Hongke case] Assembling furniture based on 3D camera
vscode插件设置——Golang开发环境配置
无代码平台多行文字入门教程
美摄问答室|美映 VS 美摄云剪辑
【机器学习】:如何对你的数据进行分类?
视频加密怎么播放_win播放器加密视频
【Inspirational】The importance of review
Google Earth Engine APP——实现ui.Select() 的设定和条件判断
知其然,知其所以然,JS 对象创建与继承
热成像测温的原理是什么呢?你知道吗?
js文字转语音播报
低代码是开发的未来吗?浅谈低代码开发平台的发展现状及未来趋势
Mysql 存储引擎简介
HCIP 交换实验
ThreadLocal详细分析
在测试集上训练,还能中CVPR?这篇IEEE批判论文是否合理?
华为开源:聚焦开源基础软件,共建健康繁荣生态
datax oracle to oracle增量同步
二叉树的基础练习









