2025-01-15🌱上海: ☀️ 🌡️+4°C 🌬️↓19km/h
# MySQL 中使用索引一定有效么?
# 简要回答
不一定有效
- 查询条件中不包含索引列
- 低基数列索引效果不佳
- 查询条件复杂且不匹配索引的顺序
- 对于小表,全表扫描可能比使用索引开销更小
# 补充回答
排查索引效果的方法:使用 EXPLAIN
命令,在查询语句前添加 EXPLAIN
可以查看 MySQL 选择的 执行计划
,了解是否使用了索引,使用了哪个索引,以及扫描的行数等信
红色为需要重要关注的信息
- id:执行计划中每个操作的唯一标识符。对于一条查询语句,每个操作都有一个唯一的 id。但是在多表 join 的时候,一次 explain 中的多条记录的 id 是相同的。
- select_type:操作的类型。常见的类型包括
SIMPLE
、PRIMARY
、SUBQUERY
、UNION
等。不同类型的操作会影响查询的执行效率。 - table:当前操作所涉及的表。
- partitions:当前操作所涉及的分区
- type:表示查询时所使用的索引类型,包括
**ALL**
、**index**
、**range**
、**ref**
、**eq_ref**
、**const**
、**system**
等。 - possible_keys:表示可能被查询优化器选择使用的索引。
- key:表示查询优化器选择使用的索引。
- key_len:表示索引的长度。索引的长度越短,查询时的效率越高。
- ref:用来表示哪些列或常量被用来与 key 列中命名的索引进行比较。
- rows:表示此操作需要扫描的行数,即扫描表中多少行才能得到结果。
- filtered:表示此操作过滤中保留的的行数占扫描行数的百分比。 值越小,说明该步骤筛选掉的数据越多
- Extra:表示其他额外的信息,包括
**Using index**
、**Using filesort**
、**Using temporary**
等。
# 扩展回答
-
Q:讲一下 type 的几种不同值都代表什么含义?可以着重说一下几个常见的。
-
A:
- system:系统表,少量数据,往往不需要进行磁盘 io
- const:使用常数索引,
MySQL
只会在查询时使用常数值进行匹配。使用唯一性索引做唯一查询 - eq_ref:当在连接操作中使用了唯一索引或者主键索引时,且连接条件是基于这个索引的等值条件时,
MySQL
通常会选择 eq_ref 连接类型,以提高查询性能。 - ref:非唯一索引扫描, 只会扫描索引树中的一部分来查找匹配的行。使用非唯一索引进行查询
- range:范围扫描, 只会扫描索引树中的一个范围来查找匹配的行。使用索引进行性范围查询
- index:全索引扫描, 会遍历索引树来查找匹配的行。不符合最左前缀匹配的查询
- ALL:全表扫描, 将遍历全表来找到匹配的行。使用非索引字段查询
以上类型速度 从上到下,由快到慢
# 在 MySQL 中建立索引时需要注意哪些事项?
# 简要回答
- 不能盲目建立索引,索引不是越多越好,索引会占用空间同时每次修改时都可能需要维护索引的数据,消耗资源
- 对于字段的值有大量重复的不要建立索引,比如性别
- 长字段不应该建立索引
- 数据表的修改频率远大于查询频率,不适合建立索引。
- 需要频繁作为条件查询的字段应该建立索引
- 经常
order by
、group by
、distinct
后面的字段建立索引
总结:查询频率高的字段适合建立索引,同时索引不在多,字段值大量重复及长字段不适合建立索引。
# 补充回答
以上并不是绝对的,比如第二条,区分度不高的字段建立索引并不一定没有用,假如我的表中有一个性别字段,只有男和女两种。一般情况下,如果表中数据量很大的话,用这个字段查询会导致没办法过滤掉很多数据,就可能没办法发挥索引的效果。但是,如果有一种特殊情况,如男女比例是 95:5,那么,这时候,如果我用 " 女 ' 作为性别的查询条件的话,还是可以走索引,并且有很大的性能提升的,原因就是因为他可以过滤掉大部分数据。走索引可以大大提升效率。
这种一般在任务表中比较多,比如任务表中有状态,两种情况:INIT 和 SUCCESS,大多数情况下,任务都是 SUCCESS 的,只有一少部分是 INIT,这时候就可以给这个字段加索引。这样当我们扫描任务表执行任务的时候,还是可以大大提升查询效率的。
# 扩展回答
-
Q: 什么情况下会导致不走索引呢?
-
A:
- 没有正确的创建索引
- 索引区分度不高
- 数据表太小
- 查询语句中,索引字段进行了函数计算,类型不一致等导致索引失效。
-
Q:上面提到了索引失效的情况,什么情况会导致索引失效呢?
-
A:
- 索引列参与计算
- 对索引列进行函数计算
- 使用 OR(如果两边字段等值且都为索引列则也会走索引)
- like 操作(符合最左前缀匹配原则可以走索引)
- 隐式类型转换
- 不等于比较(也有特殊情况)
- is not null
- order by (数据量很小的情况,数据库可能会直接在内存中进行排序,而不使用索引)
# MySQL 中的回表是什么?
# 简要回答
” 回表 “是指在使用非聚簇索引作为条件查询时,由于非聚簇索引中只存储了索引字段的值和对应的主键值,所以需要先通过非聚簇索引字段的值查询到对应的主键值,然后再根据主键值去聚簇索引查询实际的数据行,这个过程称为” 回表 “
# 补充回答
在 InnoDB 中,使用主键查询的时候,是效率更高的, 因为这个过程不需要回表。另外,依赖覆盖索引、索引下推等技术,我们也可以通过优化索引结构以及 SQL 语句减少回表的次数。
# 扩展回答
-
Q:讲一下上面提到的覆盖索引及索引下推.
-
A:
- 覆盖索引:通俗来讲,就是通过联合索引中的索引字段作为查询条件,来查询联合索引中包含的索引字段。例如联合索引为
idx_key1_key2(key1,key2)。
查询语句为select key2 from covering_index_sample where key1 = ‘keytest’;
这样查询的时候就可以通过索引树直接查询出需要的字段值而不需要进行主键回表操作了。但是不满足最左前缀匹配的话,即使是覆盖索引也无法用到索引。 - ** 索引下推:** 通俗来讲,就是把本应该在 server 端的筛选,提前在存储引擎中就进行了筛选匹配是否符合条件的索引,不符合就直接 reject 调掉,符合的然后再进行返回,这样就可以在有 like 条件查询的情况下,减少了回表次数。
- 覆盖索引:通俗来讲,就是通过联合索引中的索引字段作为查询条件,来查询联合索引中包含的索引字段。例如联合索引为