mysql> alter table SUser add index index1(email);
或
mysql> alter table SUser add index index2(email(6));
我们知道,如果选择给字符串加索引,那么索引的区分度会影响查询效率,如果同一个索引值有N个相同的前缀,就会多次回表查询,影响效率,所以怎么选择索引长度呢?
一、如何选择索引长度?
首先,你可以使用下面这个语句,算出这个列上有多少个不同的值:
mysql> select count(distinct email) as L from SUser;
然后,依次选取不同长度的前缀来看这个值,比如我们要看一下 4~7 个字节的前缀索引,可以用这个语句
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。
二、用前缀索引就不能用覆盖索引优化了
因为系统并不确定前缀索引的定义是否截断了完整信息,所以前缀索引就会回表。
三、其它方式加索引
1.倒序存储
例子:比如你要创建以身份证为索引的查询,因为身份证号在同一区县的前几位都是相同的,所以截取前几位身份证为索引的区分度并不高。
mysql> select field_list from t where id_card = reverse('input_id_card_string');
2.使用hash字段
在表中新增一个字段,用于存储hash( crc32() 这个函数)身份证号后的值。crc32有四个字节。
mysql> alter table t add id_card_crc int unsigned, add index(id_card_crc);
因为可能存在hash冲突,所以要判断身份证的全部值。
mysql> select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
3.使用倒序前缀和hash的区别
相同点:因为都对原主键进行处理,只适合等值查询,不适合范围查询。
不同点:
(1)占用额外空间看,倒序不用新增字段,但是前缀长度可能超过hash的crc32函数的4个字节,总体上差不多。
(2)cpu占用来看,倒序使用的reverse函数比crc32函数占用要少。
(3)查询效率看,hash使用的crc32函数发生hash冲突的概率比前缀的区分度小发生回表查询的概率要小。
三、思考题
如果你在维护一个学校的学生信息数据库,学生登录名的统一格式是”学号 @gmail.com", 而学号的规则是:十五位的数字,其中前三位是所在城市编号、第四到第六位是学校编号、第七位到第十位是入学年份、最后五位是顺序编号。
系统登录的时候都需要学生输入登录名和密码,验证正确后才能继续使用系统。就只考虑登录验证这个行为的话,你会怎么设计这个登录名的索引呢?