MySql 你真的会使用字符串索引吗?
志在峰巅的攀登者,不会陶醉在沿途的某个脚印之中,在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。
我们这里有一张用户表,建表语句如下
CREATE TABLE `t_user`(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID' ,
`id_card` VARCHAR(32) DEFAULT NULL COMMENT '用户身份证' ,
`u_name` VARCHAR(32) DEFAULT NULL COMMENT '用户姓名' ,
`u_phone` VARCHAR(32) DEFAULT NULL COMMENT '用户电话' ,
`u_password` VARCHAR(200) DEFAULT NULL COMMENT '用户密码' ,
`u_age` INT(11) DEFAULT NULL COMMENT '用户年龄' ,
`u_male` TINYINT(1) DEFAULT NULL ,
PRIMARY KEY(`id`) ,
KEY `id_card`(`id_card`) ,
KEY `u_phone`(`u_phone`)
) ENGINE = INNODB
这个表中有三个索引 id 的主键索引、id_card 的身份索引、手机号的索引。
1 字符串 前缀索引
我们在实际业务开发中,会有手机号密码登录的功能,所以会常有查询语句如下:
select * from t_user where u_phone='xxx' and u_password='xxx';
所以我们在 u_phone 上添加了索引,如果不添加索引,这个查询就会走全表扫描,当用户量足够大时,这个查询会足够的慢。
在这里我们为 u_phone 添加的索引,默认是11位长度的(因为手机号一般是11位),MySQL 是支持前缀索引的,所以可以考虑定义字符串的一部分作为索引,如这里我们把 u_phone 原来 11位的长度索引修改为 4 位长度的索引:
#先删除索引
ALTER TABLE t_user DROP INDEX u_phone;
#再修改
alter table t_user add index u_phone2(u_phone(4));
2 普通索引与前缀索引 查询过程分析
如执行以下查询语句
select * from t_user where u_phone='13309090909'
如果我们添加的是普通索引如下:
alter table t_user add index u_phone('u_phone');
那么在执行查询过程:
从 u_phone 索引树找到满足索引值是’13309090909’的这条记录对应的ID
然后回表到主键索引上 获取对应ID的这一条数据
然后在 u_phone 索引树取刚刚查到的位置的下一条记录,判断不浪花兄弟条件,循环结束。
这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行。
如果我们使用的是前缀索引,如下
alter table t_user add index u_phone2(u_phone(4));
那么在执行查询过程:
从 u_phone2 索引树找到满足条件的第一个记录ID;
然后再去 u_phone2 索引树找到满足条件 ‘1330’ 的ID,然后回表到ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;
重复上一步,直到在 u_phone2 上取到的值不是’1330’时,循环结束。
在这个过程中,要回主键索引取 4 次数据,也就是扫描了 4 行。
当我们再
关键就是定义前缀索引的长度的权衡问题
3 前缀索引的长度的权衡
我们可以先查询这个表中不同手机号码的用户数量
select count(distinct mobile) as L from tb_user;
比如我这个测试表中的查询结果如下:
然后,依次选取不同长度的前缀来看这个值对比一下不同数据的数量:
SELECT
count(DISTINCT LEFT(mobile , 4)) AS L4 ,
count(DISTINCT LEFT(mobile , 5)) AS L5 ,
count(DISTINCT LEFT(mobile , 6)) AS L6 ,
count(DISTINCT LEFT(mobile , 7)) AS L7
FROM
tb_user
如果选用前7个字节构建索引数据结构,重复的索引值有 190-124 = 56个,也就是说当查询到前缀正好在这56个重复索引中,需要回表查询56次进行判断。
如果选用前6个字节构建索引数据结构,重复的索引值有 190-78 = 112个,也就是说当查询到前缀正好在这112个重复索引中,需要回表查询112次进行判断。
所以需要选择 前缀7个字节。
完毕
不局限于思维,不局限语言限制,才是编程的最高境界。