当前位置:网站首页>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字段索引,查询性能稳定,有额外的存储和计算消耗,不支持范围扫描
边栏推荐
- 华为云安全云脑,让企业云化运营更放心
- 8月活动|51CTO十七周年庆,发博文得茶具/笔记本/T恤等礼品!
- iMeta | Baidu certification is completed, search "iMeta" directly to the publisher's homepage and submission link
- iMeta | German National Cancer Center Gu Zuguang published a complex heatmap visualization method
- Using .NET to simply implement a high-performance clone of Redis (2)
- Graphical Hands-on Tutorial--ESP32 OTA Over-the-Air Upgrade (VSCODE+IDF)
- 解析treeSet集合进行自定义类的排序
- audio_policy_configuration.xml配置文件详解
- CVPR 2022 | 从人体网格预测骨架,是真正的生理学骨架!
- 少即是多:视觉SLAM的点稀疏化(IROS 2022)
猜你喜欢
随机推荐
语音社交app源码——具备哪些开发优势?
数据化管理洞悉零售及电子商务运营——零售密码
A topic of map
八、MFC对话框
图文手把手教程--ESP32 OTA空中升级(VSCODE+IDF)
MySQL核心SQL:结构化查询语句SQL、库操作、表操作、CRUD
ROI LTV CPA ECPM体系讲解
Jenkins使用手册(1) —— 软件安装
Graphical Hands-on Tutorial--ESP32 One-Key Network Configuration (Smartconfig, Airkiss)
JUC (1) threads and processes, concurrency and parallelism, thread state, locks, producers and consumers
美摄问答室|美映 VS 美摄云剪辑
深度学习100例 —— 卷积神经网络(CNN)天气识别
MATLAB程序设计与应用 3.1 特殊矩阵
遍历Map的四种方法
Digital management insight into retail and e-commerce operations - retail password
Win11文件类型怎么改?Win11修改文件后缀的方法
SkiaSharp 之 WPF 自绘 粒子花园(案例版)
mae,mse,rmse分别利用sklearn和numpy实现
ThreadLocal详细分析
CVPR 2022 | 从人体网格预测骨架,是真正的生理学骨架!