场景:验证邮箱

mysql> create table SUser(
ID bigint unsigned primary key,
email varchar(64),
... )engine=innodb;
mysql> select f1, f2 from SUser where email='xxx';

分析:

       1. 如果email上没有索引,那么将会做全盘扫描

2.可以运用前缀索引(运用字符串的一部分作为索引);

分析比较:

mysql> alter table SUser add index index1(email); 

mysql> alter table SUser add index index2(email(6));


第 一个语句创建的 index1 索引里面,包含了每个记录的整个字符串;而第二个语句创建的 index2


索引里面,对于每个记录都是只取前 6 个字节。



(九)给字符加索引_mysql



(九)给字符加索引_mysql_02


从两图中你可以看到,由于 email(6) 这个索引结构中每个邮箱字段都只取前 6 个字节(即: zhangs ),所以占用的空间会更小,这就是使用前缀索引的优势。 但,这同时带来的损失是,可能会增加额外的记录扫描次数。


 


前缀索引查询步骤说明:

   1. 从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;
   2. 到主键上查到主键值是ID1的行,判断出email的值不是’zhangssxyz@’,这行记录丢 弃;
   3. 取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取 整行然后判    断,这次值对了,  将这行记录加入结果集;
   4. 重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。

跟全盘扫描比较:

    1. 从index1索引树找到满足索引值是’zhangssxyz@’的这条记录,取得ID2的值;
    2. 到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;
    3. 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足 email='zhangssxyz@’的条件了,循环结束。

结论:通过这个对比,你很容易就可以发现,使用前缀索引后,可能会导致查询语句读数据的次数变 多。

解决:又不全盘扫描,避免前缀索引的额外的增加的次数;

怎么解决:使用好前缀索引的话,定义好长度,就可以节省空间,又不用额外增加太多的查询成本;

使用前缀索引很可能会损失区分度,所以你需要预先设定一个可以接受的损失比例,比如 5%。然后,在返回的L4~L7中,找出不小于 L * 95%的值,假设这里L6、L7都满足,你就可以 选择前缀长度为6;

继续分析前缀索引:

    1.使用前缀索引,会增加扫描行数(但是创建长度够长的,又增加磁盘空间,数据页放下的数据记录就更少;但是要是减少索引长度,又会丧失索引的区分度,并且会反而不如全盘扫描);

    2.还有就是不能再使用覆盖索引;

所以要去寻找更好的增加索引办法:

   1.倒叙存储;

   2.使用hash字段;

倒叙存储:

    如果是身份证查询的haul,就把它倒过来查询,每次查询的时候这么写:

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


由于身份证号的最后 6 位没有地址码这样的重复逻辑,所以最后这 6 位很可能就提供了足够的区


分度。当然了,实践中你不要忘记使用 count(distinct) 方法去做个验证。


使用hash 字段:


你可以在表上再创建一 个整数字段,来保存身份证的校验码, 同时在这个字段上创建索引。


 


mysql> alter table t add id_card_crc int unsigned, 
add index(id_card_crc);

mysql>select field from t where id_card_crc=crc32('input_id_card')
and id_card=id_input_id_card


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


 


倒叙存储和使用hash字段增加索引的利弊:


 


1.


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


2.


在 CPU 消耗方面,倒序方式每次写和读的时候,都需要额外调用一 次 reverse 函数,而 hash 字段的方式需要额外调用 一


次 crc32() 函数。如果只从这两个函数的计算复杂度来看的 话, reverse 函数额外消耗的 CPU 资源会更小些。


3.


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