第一个语句创建的index1索引里面,包含了每个记录的整个字符串;
第二个语句创建的index2 索引里面,对于每个记录都是只取前6个字节
mysql> alter table SUser add index index1(email);
mysql> alter table SUser add index index2(email(6));
这两个索引定义下分别执行下面查询语句:
select id,name,email from SUser where email='zhangssxyz@xxx.com';
使用前缀索引,定义好长度,就可以既节省空间,又不用额外增加太多的查询成本。
区分度,区分度越高越好
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。
下面两个SQL语句:
select id,email from SUser where email='zhangssxyz@xxx.com';
select id,name,email from SUser where email='zhangssxyz@xxx.com';
使用前缀索引就用不上覆盖索引对查询性能的优化了。
比如,我们国家的身份证号,一共18位,其中前6位是地址码,所以同一个县的人的身份证号前 6位一般会是相同的。还有没有别的处理 方法呢?这种方法,既可以占用更小的空间,也能达到相同的查询效率。
select field_list from t where id_card = reverse('input_id_card_string');
使用 reverse() 函数把数字倒过来,可以用最后6位的区分度创建前缀索引,使用count(distinct)方法去做个验证 。
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'
用crc32()这个函数得到校验码填到这个新字段。
倒序存储和使用hash字段的异同点 :
相同点: 都不支持范围查询。 倒序存储不支持范围查询;hash字段也只能支持等值查询。
不同点:
字符串字段创建索引的场景