哪个模块负责选择索引?

选择索引是MySQL Server层优化器的工作。

选择索引的依据

扫描行数

如何计算扫描行数?
由于MySQL在真正执行语句之前,并不能精确地知道满足这个条件的记录有多少条,而只能根据统计信息来估算记录数,这个统计信息就是索引的“区分度”,又称为“基数”。

一个索引上不同的值越多,这个索引的区分度就越好。可以通过show index看到每个索引的区分度。如下图中的cardinality字段。
image.png
由于把整张表的数据取出来一行一行统计的代价太高了,因此这个索引基数是通过采样统计的方式获得的。
如何进行采样统计?
InnoDB默认会选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。
什么时候重新统计?
由于数据表是会持续更新的,索引统计信息也不会固定不变,所以,当变更的数据行超过1/M的时候,会自动触发重新做一次索引统计。
存储索引统计结果的方式
可以通过设置参数innodb_stats_persistent来选择

  • 设置为on时,表示统计信息会持久化存储,这时,默认的N是20,M是10
  • 设置为off时,表示统计信息只存储在内存中。这时,默认的N是8,M是16

当发现MySQL的索引统计信息不准确时,可以通过analyze table t来重新统计索引信息。

是否需要回表

是否排序

是否使用临时表

强制MySQL使用指定索引

force index(a),当优化器没有选择正确的索引时,可以试用贴force index来矫正MySQL的选择。
MySQL会根据此法解析的结果分析出可能可以使用的索引作为候选项,然后在候选列表中依次判断每个索引需要扫描多少行,如果force index指定的索引在候选列表中,就直接选择这个索引。

引导MySQL使用我们期望的索引

新建一个更合适的索引来提供给优化器选择