这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战
前缀索引的使用
大家一定都了解登录的功能吧?很多登录功能都支持邮箱登录,那我们在后台一定会出现这么一条sql。 假设我们的表结构如下所示:
create table t_User(
ID bigint unsigned primary key,
name varchar(64),
email varchar(64),
...
)engine=innodb;
复制代码
我们知道,如果我们没有给email字段添加索引,那这条sql一定会全盘扫描。所以我们给email添加索引,如下所示:
alter table t_User add index index1(email);
复制代码
创建的索引树将如下图所示:
我们执行这条SQL:
select x1 from t_User where email = '[email protected]';
复制代码
- 当我们使用该index1索引时,引擎的执行顺序如下所示:
1.从index1 索引树找到满足索引是’[email protected]’的这条记录,取得 ID1 的值;
2.到主键上查到主键值是 ID1 的行,判断 email 的值是正确的,将这行记录加入结果集;
3.取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email='[email protected]’的条件了,循环结束。
这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行,我们只做一次回表的操作。
但是MySQL支持前缀索引,也就是说,我们可以把字符串的某一部分作为索引,如下所示:
alter table t_User add index index2(email(6));
复制代码
该语句取email字段的前6个字节作为索引。
创建的索引树将如下图所示:
很显然,取前6个字节作为索引的index2占用空间更少,但是可能会增加额外的扫描次数。
我们执行这条SQL:
select x1 from t_User where email = '[email protected]';
复制代码
- 当我们使用index2索引时,引擎的执行顺序如下所示:
-
从 index2 索引树找到满足索引值是’budong’的记录,找到的第一个是 ID1;
-
到主键上查到主键值是 ID1 的行,判断出 email 的值不是’[email protected]’,这行记录丢弃;
-
取 index2 上刚刚查到的位置的下一条记录,发现仍然是’budong’,取出 ID2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;
-
重复上一步,直到在 idxe2 上取到的值不是’budong’时,循环结束。
在这个过程中,要回主键索引取 4 次数据,也就是扫描了 4 行。所以我们发现,使用前缀索引后,导致我们读数据的次数变多了。
但如果我们定义的index2是email(9),那索引第一次取到的就会是‘budong112’,满足此前缀的只有一个,所以只要扫描一行就结束了。
小结
也就是说使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询 成本。