MySQL 索引失效问题
索引失效的情况:
- 使用 like ‘%abc’或者like ‘%abc%’
- 查询列参与了函数计算(并没有使用函数索引)
- 数据不够离散,扫描的行数和加载索引的成本超过了全表扫描
- 联合索引没有使用最左匹配,或者在范围运算(>,<,<>)等运算的后面
- where中索引列有运算
除了上面的几个明显的问题外,还有索引的选择问题。MySQL 在执行一段 sql 的时候,会先决定使用哪一个索引,如果 选了一个性能比较差的索引,即使走了索引,也会带来性能问题。
对上面的第 4 条做一个例子说明:
- 定义 abcd 字段一个联合索引
- 如果使用 a>0 and b=1 .. 则 a 本身走索引,但 a 后面的字段都不走索引
- a=1 and b=1 and c>1 and d=1 这个例子 只有 d 不走索引,如果 索引顺序更改为 abdc 则都会走索引。
准备工作
1 | create database ITTest; |
Explain 查看索引使用情况
各个字段的含义
1 | mysql> EXPLAIN SELECT `birday` FROM `user` WHERE `birthday` < "1990/2/2"; |
索引选择的决定的因素
- 如果在一个 sql 中,有使用了两个索引,是否会同时使用?如果不是,那如何决定使用哪一个?
- 如果有一个字段有单独的索引,又符合联合索引的最左匹配原则,索引会怎么选?
MySQL 索引的选取是基于成本计算的,影响查询成本的因素有 扫描行数、是否需要临时表以及是否需要排序**等。
成本的决定因素很多,就那扫描行数来说,影响扫描行数最大的因素是数据的离散度
,但是数据又是动态变化的,所以在使用的离散度比较低的索引的时候需要注意后续的索引变化。例如:
1 | select * from user where userSex=0 and userStatus=0 and birthDate>'1897-01-01' |
分析下上面的两个sql 的执行速度那个快:
- 上面的sql 不同点是 userSex 的的过滤条件
- 根据上面建立的两个索引规则,有可能走到联合索引和 userStatus 单独的索引
- 在执行筛选的时候,
如果这个时候,MySQL 发现 userSex 走索引的成本小于全表扫描,则可能会走索引下推
- 使用 in 的时候,userSex 的字段直接默认走全表扫描,不会计算成本