初学MySQL—如何给字符串加索引?

如何给字符串加索引?

  • 索引的选择
  • 前缀索引对覆盖索引的影响
  • 其它方式
  • 总结

索引的选择

例如对于一个支持邮箱登录的系统,如何在这个字段上建立合理的索引?
在email字段上创建索引的语句如下:

alter table SUser add index index1(email);
alter table SUser add index index2(email(6));

创建的index1索引中,包含了每个记录的整个字符串;
创建的index2索引中,每个记录只取前6个字节;

初学MySQL—如何给字符串加索引?_第1张图片
初学MySQL—如何给字符串加索引?_第2张图片
但是使用前缀索引,可能会导致查询语句的读数据的次数变多;
使用前缀索引,定义好长度,就可以既能节省空间,也不用额外的增加查询成本

建立索引应当关注的是区分度,区分度越高,重复的键值就越少
采用以下语句来判断该列上有多少不同的值:

select count(distinct email) as L from SUser;

依次选取不同长度的前缀来看这个值:

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;

前缀索引对覆盖索引的影响

前缀索引可能会增加扫描次数,也会影响性能;

使用了前缀索引就用不上覆盖索引对查询性能的优化了,也是使用时需要考虑的一个因素;

其它方式

对于邮箱这种字符串,使用前缀索引的效果可能还不错,但是遇到区分度不够高的情况,例如身份证号有18位,前六位是地址码,那如果创建长度12以上的前缀索引,才能够满足区分度的话,索引选取的越长,占用的磁盘空间就越大,相同数据页放入的索引值就越少,搜索的效率也就会越低。

如何既可以占用更小的空间,又能达到相同的查询效率呢?

  • 第一种是采用倒序存储,像身份证的最后六位没有地址码这样的重复逻辑,最后六位提供了很好的区分度,每次查询的语句如下:
select field_List from t where id_card = reverse("input_id_card_string");
  • 第二种是采用hash字段,在表上创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引:
mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);

每次插入新记录,都使用crc32()这个函数得到校验码填写到新字段中,由于校验码可能存在hash冲突,需要在查询语句中判断id_card的值是否精确相同。

两种方式的异同点:
相同点:
二者都不支持范围查询,倒序存储无法采用范围查询,hash字段只支持等值查询;
不同点:

  • 占用空间来看
    倒序存储在主键索引上,不会消耗额外的存储空间;
    Hash字段需要增加一个字段;

  • CPU消耗
    倒序方式每次读写都需要额外调用一次reverse函数;
    Hash字段的方式需要额外调用一次crc32()函数;
    计算复杂度来看,reverse函数额外消耗的CPU资源会更小一些;

  • 查询效率
    hash字段查询性能相对稳定,哈希冲突的概率小,平均扫描行数为1;
    倒序存储采用前缀索引,增加扫描行数;

总结

  • 直接创建索引占用空间;
  • 前缀索引节省空间,但会增加扫描次数,并且不能使用覆盖索引;
  • 倒序存储,在进行前缀索引,解决了字符串本身前缀区分度不够的问题;
  • 创建hash字段索引,查询性能稳定,但是有额外的存储和计算消耗,并且不支持范围查询;

你可能感兴趣的:(MySQL,Mysql学习之路)