这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战
某些情况下,希望直接通过某字段作为条件进行查询。如果该字段没有索引,则该语句只能做全表扫描。 那么如何给该字符串字段添加索引呢?
给字符串字段添加索引的方法
- 前缀索引 - 定义字符串的一部分作为索引 - 若创建索引的语句不指定前缀长度 - 索引会包含整个字符串
EG:1. alter table SUser add index index1(email);
2. alter table SUser add index index2(email(6));- 前缀索引的优劣
- 占用的空间更小
- 可能会增加额外的记录扫描次数
- 具体流程 - select id, name, email from SUser where email='zhangssxyz@xxx.com';
- index1[email整个字符串的索引结构]
- 从index1索引树找到满足索引值'zhangssxyz@xxx.com'的这条记录,取得ID的值;
- 到主键上查到主键值是ID的行,判断email的值是正确的,将这行记录加入结果集;
- 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email='XX'的条件,循环结束;
只需要回主键索引取一次数据,系统认为只扫描了一行。
- index[email(6)索引结构]
- 从index2索引树找到满足索引值是'zhangs'的记录,找到的第一个是ID1;
- 到主键上查找到主键值是ID1的行,判断email的值不是'zhangssxyz@xxx.com', 这行记录丢弃;
- 取index2上刚刚查到的位置的下一条记录,发现仍然是'zhangs',取出ID2;
- 再到ID索引上取整行然后判断,值对,将这行记录加入结果集;
- 重复第3-4步,知道index2索引树上取到的值不是'zhangs'时,循环结束;
要回主键索引取4次数据 - 扫描了4行
使用前缀索引,可能会导致查询语句读数据的次数变多 使用前缀索引,定义好长度,可以节省空间+不额外增加太多的查询成本
- index1[email整个字符串的索引结构]
如何确定使用多长的前缀?
3. 前缀索引对覆盖索引的影响建立索引时关注的是区分度 - 区分度越高越好 - 重复的键值越少 通过统计索引上有多少个不同的值来判断要使用多长的前缀 预先设定可接受的损失比例 - 找出不小于L*95%的值
使用前缀索引无法使用覆盖索引对查询性能的优化 - 系统并不确定前缀索引的定义是否截断了完整信息,还是会回到主键上查询 - 前缀索引的优劣
- 其他方式 - 前缀的区分度不好时
- 倒序存储 - 例如身份证后6位有足够的区分度,前面的没有
- hash字段 - 表上再创建一个整数字段 - 保存身份证的校验码,在这个字段上创建索引
- 倒序存储和hash字段的异同:
- 都不支持范围查询
- 倒序了怎么按原序范围查
- hash - 等值查询
- 都不支持范围查询
| 各类 | 倒序存储 | hash字段 |
|---|---|---|
| 占用的额外空间 | 主键索引上,不消耗 | 需增加一个字段,倒序存储的前缀长度稍长,消耗基本差不多 |
| CPU消耗 | 每次读、写 - 额外调用一次reverse函数 | hash 额外调用crc32()函数 - 计算复杂度来看,reverse函数额外消耗的CPU资源会更小 |
| 查询效率 | 前缀索引 - 增加扫描行数 | 查询性能相对更稳定,crc32算出来有冲突的值概率很小。平均行数接近1 |