当前位置:网站首页>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字段索引,查询性能稳定,有额外的存储和计算消耗,不支持范围扫描
边栏推荐
猜你喜欢
随机推荐
AWS Lambda related concepts and implementation approach
Heap Sort
使用.NET简单实现一个Redis的高性能克隆版(二)
Super Learning Method
8月活动|51CTO十七周年庆,发博文得茶具/笔记本/T恤等礼品!
微信小程序自定义组件-城市选择「建议收藏」
RAID介绍及RAID5配置实例
Business collocations
Digital management insight into retail and e-commerce operations - retail password
Graphic and text hands-on tutorial--ESP32 MQTT docking EMQX local server (VSCODE+ESP-IDF)
MySQL core SQL: SQL structured query statements, library, table operation, CRUD
再次搞定 Ali 云函数计算 FC
第二批养老理财试点产品发行 一小时销售20亿元
MySQL核心SQL:结构化查询语句SQL、库操作、表操作、CRUD
江西发布紧急通知:全面开展涉校涉生安全隐患大排查
Mysql 存储引擎简介
HCIP 第十八天
[easyUI]修改datagrid表格中的值
【励志】复盘的重要性
开源一夏|ArkUI如何自定义弹窗(eTS)