本文已收录GitHub,更有互联网大厂面试真题,面试攻略,高效学习资料等mysql
假设创建一个支持邮箱登陆的用户表,对于邮件字段来讲,能够有如下几种创建索引的方式:git
①. 直接对整个字符串创建索引github
alter table SUser add index index1(email);
②. 对整个字符串的前一部分创建索引 - 前缀索引面试
alter table SUser add index index2(email(6));
方式 2 相较于 方式 1 来讲,利用前缀索引,占用的空间更小。但有可能形成性能的损失,读取数据的次数变多。sql
假设在 user 表中存在2986706524@gmail.com, 2986706524@qq.com , 2986706524@xxx.com, 三条记录。网络
有这样一条语句 select id,name,email from SUser where email='2986706524@xxx.com';ide
使用 index1 索引时,流程以下:函数
使用 index2 索引:性能
看这个过程,很容易发现,前缀索引会增长查询语句读取数据的次数。学习
但若是将前缀索引的 email(6) 改为 email(7),就会减小查询的次数,对应在主键索引上只搜索一次。这就说明,若是能合适的设置前缀索引的长度,就能在空间和效率上取得平衡。
如何找到合适的前缀索引长度
在创建索引时,应该去关注区分度,区分度越高,则说明重复的键值越少。
能够经过执行查询来统计列上有多少不一样的值。
mysql> select count(distinct email)as L, 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%, 用 L 的数量 * 区分度比例(1-5%=95%),而后看在 L4 到 L7 中哪一个知足。
前缀索引的影响
在以前覆盖索引的文章中,若是查询的列的信息被包含在二级索引上,那么就能够避免回表的过程,进而减小查询次数,提供效率。但若是在创建索引时,使用了前缀索引,那么不管满不知足覆盖索引的规则,都会回表。由于系统不能肯定前缀索引是否截取了完成信息,进而必须作一次判断。
也就是说,前缀索引除了会增长查询语句的次数,还会禁止使用覆盖索引。
对于邮箱这类的字符串来讲,因为前几位有较大的区分度,因此用前缀索引还不错。但若是是区分度很差的状况,好比身份证,前 6 位都是地址码,不少人都会同样。这时若是想要使用前缀索引,就须要至少 12 位以上,对应查询效率和空间都不是很合适。
一个比较好的办法是将字符串倒序存储,将区分度高的字符开头。
例如:
mysql> select field_list from t \ where id_card = reverse('input_id_card_string');
在网络传输时,CRC - 循环冗余校验被用于检验文件。对应在 MySQL 里也有这个函数,crc32().
该函数的返回范围是 0-4294967296 也就是 4 字节,相对于其余字符串来讲,属于较短的长度。
在建立表时,可再建立一个整数字段,来保存这类字符串,如身份证的校验码(crc32()的返回值), 并为该字段建立索引。
如:
mysql> alter table t add id_card_crc int unsigned, \ add index(id_card_crc);
在插入记录时,将 crc32() 的结果插入到记录中。
但因为 crc32() 只有 32 位的特性,容易发生 hash 碰撞,就是说可能两个字符串通过计算后获得相同的验证码。这时就存在冲突,因此还须要判断下查询的值是否一致。
如:
mysql> select field_list from t where \ id_card_crc=crc32('input_id_card_string') and \ id_card='input_id_card_string'
咱们知道,MySQL 中使用的是 B+ 树来存储索引的,这天然就是有序的,因此前缀查询就支持范围查询。
而 Hash 字段和倒序查询两种方式就不行了,倒序查询是按照倒序字符串存储的,而 hash 字段和字符串自己也没有关系,这就意味着这两种方式是不支持范围查询的。
在占用空间上来讲,倒序存储占用的是和普通索引的同样的空间。而 hash 字段,须要增长一个字段来存在 hash 校验码。
在 CPU 消耗,倒序时,每次读和写都须要调用 reverse 函数。hash 方式须要额外调用 crc32() 函数。两个函数实现来看,reverse 函数 CPU 消耗会少些。
在查询效率上,hash 字段查询性能更好稳定些。虽然可能存在冲突的状况,但几率很小。而倒序存储仍是用前缀索引的方式,会额外增长扫描行数。
总结一下,通常提升查询字符串的效率有以下方式: