场景:验证邮箱
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));
前缀索引查询步骤说明:
1. 从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;
2. 到主键上查到主键值是ID1的行,判断出email的值不是’[email protected]’,这行记录丢 弃;
3. 取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取 整行然后判 断,这次值对了, 将这行记录加入结果集;
4. 重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。
跟全盘扫描比较:
1. 从index1索引树找到满足索引值是’[email protected]’的这条记录,取得ID2的值;
2. 到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;
3. 取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足 email='[email protected]’的条件了,循环结束。
结论:通过这个对比,你很容易就可以发现,使用前缀索引后,可能会导致查询语句读数据的次数变 多。
解决:又不全盘扫描,避免前缀索引的额外的增加的次数;
怎么解决:使用好前缀索引的话,定义好长度,就可以节省空间,又不用额外增加太多的查询成本;
使用前缀索引很可能会损失区分度,所以你需要预先设定一个可以接受的损失比例,比如 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');
使用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