持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
索引简介
Mysql默认的存储引擎是InnoDB。它采用 B+Tree 作为索引的数据结构,叶子节点保存数据本身。在创建表时,InnoDB 默认会创建一个主键索引,也就是聚簇索引,其他索引都属于二级索引。
InnoDB 存储引擎根据索引类型不同,分为聚簇索引 和 二级索引。它们的区别在于,聚簇索引的叶子节点存放的是实际数据,所有完整的用户数据都存放在聚簇索引的叶子节点,而二级索引的叶子节点存放的是主键值,而不是实际值。
失效情况
使用左或者左右模糊匹配
使用 like %xx 或者 like %xx% 这两种方式会造成索引失效,执行全表扫描
原因
索引 B+ 树是按照 “索引值” 有序排列存储,只能根据前缀进行比较
对索引使用函数
如果查询条件中对索引字段使用函数,就会导致索引失效。
select * from user where length(name) > 0;
原因
索引保存的是索引字段的原始值,而不是经过函数计算后的值,自然就没办法走索引了。
解决
从Mysql 8.0 开始,索引特性增加了函数索引,即可以针对函数计算后的值建立一个索引。
对 length(name) 的计算结果建立一个名为 idx_name_length 的索引
alter table t_user add key idx_name_length ((length(name)));
对索引进行表达式计算
select * from user where id + 1 = 10;
原因
原因跟对索引使用函数差不多。因为索引保存的是索引字段的原始值,而不是 id + 1 表达式计算后的值,所以无法走索引,只能通过把索引字段的取值都取出来,然后依次进行表达式的计算来进行条件判断,因此采用的就是全表扫描的方式。
对索引隐式类型转换
原因
如果索引字段是字符串类型,但是在条件查询中,输入的参数是整型的话,你会在执行计划的结果发现这条语句会走全表扫描。
MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。
联合索引非最左匹配
对主键字段建立的索引叫做聚簇索引,对普通字段建立的索引叫做二级索引。
那么多个普通字段组合在一起创建的索引就叫做联合索引,也叫组合索引。
创建联合索引时,我们需要注意创建时的顺序问题,因为联合索引 (a, b, c) 和 (c, b, a) 在使用的时候会存在差别。
原因
在联合索引的情况下,数据是按照索引第一列排序,第一列数据相同时才会按照第二列排序。
如果我们想使用联合索引中尽可能多的列,查询条件中的各个列必须是联合索引中从最左边开始连续的列。如果我们仅仅按照第二列搜索,肯定无法走索引
WHERE 子句中的 OR
在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。
原因
这是因为 OR 的含义就是两个只要满足一个即可,因此只有一个条件列是索引列是没有意义的,只要有条件列不是索引列,就会进行全表扫描。
总结
使用左或者左右模糊匹配的时候,也就是 like %xx 或者 like %xx%这两种方式都会造成索引失效;
在查询条件中对索引列使用函数,就会导致索引失效。
在查询条件中对索引列进行表达式计算,也是无法走索引的。
MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。如果字符串是索引列,而条件语句中的输入参数是数字的话,那么索引列会发生隐式类型转换,由于隐式类型转换是通过 CAST 函数实现的,等同于对索引列使用了函数,所以就会导致索引失效。
联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配,否则就会导致索引失效。
在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。