暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL如何建立前缀索引

ITwords 2021-08-26
2059


公众号后台回复“学习+JavaSE”,即可免费获得学习资料





前言:本公众号将推出系列性的知识分享,以专题或者模块的方式,向读者分享学习体会和心得。所以想要学习的朋友可以点击关注,一起学习。


上一篇文章介绍了什么是前缀索引,这篇介绍如何建立前缀索引。


我们在建立索引时关注的是区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少。因此,我们可以通过统计索引上有多少个不同的值来判断要使用多长的前缀。

首先,你可以使用下面这个语句,算出这个列上有多少个不同的值:

    select count(distinct email) as L from user

    然后,依次选取不同长度的前缀来看这个值,比如我们要看一下4~7个字节的前缀索引,可以用这个语句:

      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。

      但是依旧会遇到问题,例如:将身份证作为索引,那么索引的长度应该定义为几位呢?定义的太短会增加查询的次数和时间,定义的太长又会增加空间的存储,导致查询变慢。遇到这样的问题,如何解决呢?当然有解决的办法。

      第一种方式是使用倒序存储。如果存储身份证号的时候把它倒过来存,每次查询的时候,可以这么写:

        select field_list from t where id_card = reverse('input_id_card_string');

        由于身份证号的最后6位没有地址码这样的重复逻辑,所以最后这6位很可能就提供了足够的区分度。当然了,实践中你不要忘记使用count(distinct)方法去做个验证。

        第二种方式是使用hash字段。你可以在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引。

          alter table t add id_card_crc int unsigned, add index(id_card_crc);
            补充:crc32的概念和原理
            CRC校验实用程序库 在[数据存储](https://baike.baidu.com/item/数据存储/9827490)
            和[数据通讯](https://baike.baidu.com/item/数据通讯/1006573)领域,为了保证数据的正确,就不得不采用检错的手段。在诸多检错手段中,CRC是最著名的一种。
            CRC的全称是[循环冗余校验](https://baike.baidu.com/item/循环冗余校验/3219009)。

            然后每次插入新记录的时候,都同时用crc32()这个函数得到校验码填到这个新字段。由于校验码可能存在冲突,也就是说两个不同的身份证号通过crc32()函数得到的结果可能是相同的,所以你的查询语句where部分要判断id_card的值是否精确相同。

              select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'

              这样,索引的长度变成了4个字节,比原来小了很多。

              两种方式的异同点

              它们的区别,主要体现在以下三个方面:

              首先,它们的相同点是,都不支持范围查询。倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出身份证号码在[ID_X, ID_Y]的所有市民了。同样地,hash字段的方式也只能支持等值查询。

              不同点:

              1. 从占用的额外空间来看,倒序存储方式在主键索引上,不会消耗额外的存储空间,而hash字段方法需要增加一个字段。当然,倒序存储方式使用4个字节的前缀长度应该是不够的,如果再长一点,这个消耗跟额外这个hash字段也差不多抵消了。

              2. 在CPU消耗方面,倒序方式每次写和读的时候,都需要额外调用一次reverse函数,而hash字段的方式需要额外调用一次crc32()函数。如果只从这两个函数的计算复杂度来看的话,reverse函数额外消耗的CPU资源会更小些。

              3. 从查询效率上看,使用hash字段方式的查询性能相对更稳定一些。因为crc32算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。


              今天的内容到这里就结束了,大家不懂的可以私我哈!!



              喜欢的同学可以点击“在看”,并且关注ITwords微信公众号,第一时间获取更新内容。您的转发和点赞将是我原创的动力,感谢您的支持。


              扫描二维码

              获取更多精彩

              ITwords



              尾言:下一篇深入索引(三)


              往期回顾:

              MySQL之覆盖索引的“回表”优化和最左前缀原则

              文章转载自ITwords,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论