阿里百度华为如何使用MySQL给字符串加索引(上)

现在主流网站都支持手机号登录,如何在手机号这样的字符串字段建立合适的索引呢?

假设,你现在维护一个支持邮箱登录的系统,用户表是这么定义的:


create table SUser(
    ID bigint unsigned primary key,
    email varchar(64), 
    ... 
)engine=innodb; 

要使用邮箱登录,会有语句:

select f1, f2 from SUser where email='xxx';

若email字段无索引,该语句只能全表扫描。


MySQL支持前缀索引,可定义字符串的一部分作为索引。

若创建索引的语句不指定前缀长度,那么索引默认包含整个字符串。


比如,这俩在email字段创建索引的语句:

alter table SUser add index index1(email);
alter table SUser add index index2(email(6));
  • 第一个语句创建的index1索引,包含每个记录的整个字符串

阿里百度华为如何使用MySQL给字符串加索引(上)


  • 第二个语句创建的index2索引,对每个记录都只取前6个字节

阿里百度华为如何使用MySQL给字符串加索引(上)

可见,email(6)索引结构中每个邮箱字段都只取前6字节(zhangs),占用空间更小,这就是前缀索引优势。

这同时带来损失:可能会增加额外的记录扫描次数。

看看下面这语句,在这俩索引定义分别怎么执行。

select id,name,email from SUser where email='zhangssxyz@xxx.com';

如果使用index1,执行顺序如下:


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


该过程,只需回主键索引取一次数据,所以系统认为只扫描一行。

如果使用是index2,执行顺序如下:

阿里百度华为如何使用MySQL给字符串加索引(上)

1 确定前缀长度


在建立索引时我们关注的是区分度,区分度越高越好。区分度越高,重复的键值越少。因此可通过统计索引上有多少不同值判断要使用多长前缀。


可使用如下语句,计算该列上有多少不同值

select count(distinct email) as L from SUser;

依次选取不同长度前缀来测该值,比如看4~7个字节前缀索引:

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。

上一篇:事件注册机制 - Registry


下一篇:深入了解db file parallel read等待事件