MySQL实战45讲Day10----给字符串字段加索引

一、给字符串字段加索引方法:

    1、对于“select f1, f2 from SUser where email='xxx';”这个语句,如果email这个字段上没有索引,那么这个语句就只能做全表扫描。同时,MySQL是支持前缀索引的,也就是说,可以定义字符串的一部分作为索引。默认地,如果创建索引的语句不指定前缀长度,那么索引就会包含整个字符串。

    2、在email字段上创建索引的两种方法语句:

            mysql> alter table SUser add index index1(email);index1索引里面,包含了每个记录的整个字符串;
            mysql> alter table SUser add index index2(email(6));index2索引里面,对于每个记录都是只取前6个字节。

    3、前缀索引的优缺点:

        由于email(6)这个索引结构中每个邮箱字段都只取前6个字节,所以占用的空间会更小,这就是使用前缀索引的优势。但这同时带来的损失是可能会增加额外的记录扫描次数。使用前缀索引后,可能会导致查询语句读数据的次数变多。所以,使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。

    4、确定使用多长的前缀的方法:

        在建立索引时关注的是区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少。因此,通过统计索引上有多少个不同的值来判断要使用多长的前缀。首先使用“ select count(distinct email) as L from SUser; ”这个语句,算出这个列上有多少个不同的值,然后,依次选取不同长度的前缀来看这个值,比如我们要看一下4~7个字节的前缀索引,可以用这个语句:
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语句1:select id,email from SUser where email='[email protected]';
SQL语句2:select id,name,email from SUser where email='[email protected]';
        相比SQL语句1,SQL语句2只要求返回id和email字段。所以,如果使用index1(即email整个字符串的索引结构)的话,可以利用覆盖索引,从index1查到结果后直接就返回了,不需要回到ID索引再去查一次。而如果使用index2(即email(6)索引结构)的话,就不得不回到ID索引再去判断email字段的值。即使将index2的定义修改为email(18)的前缀索引,这时候虽然index2已经包含了所有的信息,但InnoDB还是要回到id索引再查一下,因为系统并不确定前缀索引的定义是否截断了完整信息。也就是说,使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是在选择是否使用前缀索引时需要考虑的一个因素。

三、遇到前缀的区分度不够好时,操作方法:

        1、使用倒序存储。(select field_list from t where id_card = reverse('input_id_card_string');
        2、使用hash字段。然后每次插入新记录的时候,都同时用crc32()这个函数得到校验码填到这个新字段。由于校验码可能存在冲突,也就是说两个不同的元素通过crc32()函数得到的结果可能是相同的,所以查询语句where部分要判断id_card的值是否精确相同。
(增: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'

四、使用倒序存储和使用hash字段这两种方法的异同点:

        它们的相同点是,都不支持范围查询。倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出在某个范围内的所有元素了。同样地,hash字段的方式也只能支持等值查询。

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

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

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

你可能感兴趣的:(MySQL实战45讲Day10----给字符串字段加索引)