Kaze
Kaze
Published on 2023-10-20 / 15 Visits
0
0

10MySQL为什么有时候会选错索引?

文章地址

总结:

优化器的逻辑

优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。优化器会根据扫描行数、是否使用临时表、是否排序等因素进行综合判断,评估每个索引的执行代价。

扫描行数是怎么判断的?

MySQL根据统计信息来估算记录数。一个索引上不同的值的个数,我们称之为“基数”(cardinality)。可以使用 show index 方法,看到一个索引的基数。

MySQL 是怎样得到索引的基数的呢?

采样统计的时候,InnoDB 默认会选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。

当变更的数据行数超过 1/M 的时候,会自动触发重新做一次索引统计。

在 MySQL 中,有两种存储索引统计的方式,可以通过设置参数 innodb_stats_persistent 的值来选择:

  • 设置为 on 的时候,表示统计信息会持久化存储。这时,默认的 N 是 20,M 是 10。

  • 设置为 off 的时候,表示统计信息只存储在内存中。这时,默认的 N 是 8,M 是 16。

analyze table 命令,可以用来重新统计索引信息。在实践中,如果你发现 explain 的结果预估的 rows 值跟实际情况差距比较大,可以采用这个方法来处理。

索引选择异常的处理

对于由于索引统计信息不准确导致的问题,你可以用 analyze table 来解决。而对于其他优化器误判的情况,你可以在应用端用 force index 来强行指定索引,也可以通过修改语句来引导优化器,还可以通过增加或者删除索引来绕过这个问题。


Comment