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

发布时间 2023-06-28 23:47:00作者: 帅的雅痞

以下内容出自《MySQL 实战 45 讲》

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

优化器的逻辑

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

影响优化器选择的判断标准:

  • 扫描行数
  • 临时表
  • 是否排序

扫描行数

MySQL 在真正执行语句之前,会根据统计信息来估算记录数。这个统计信息就是索引的 “区分度“。显然,索引上不同的值越多,索引的区分度就越好

索引上不同值的个数,称之为 “基数”。即基数越大,索引区分度越好

MySQL 是怎么得到索引的基数呢? 答案是采样统计,因为精确统计代价太高了。

采样统计的计算方式:InnoDB 默认选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,再乘以这个索引的页面数,就得到了这个索引的基数。

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

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

  • 设置为 ON(默认): 表示统计信息会持久化存储,此时,默认的 N 是 20,M 是 10。
  • 设置为 OFF: 表示统计信息只存储在内存中。此时,默认的 N 是 8,M 是 16。

由于索引统计信息不准确导致的问题,可以用 analyze table table_name 来重新统计索引信息。

在实践中,如果你发现 explain 的结果预估的 rows 值跟实际情况差距比较大,可以采用这个方法来处理。

索引选择异常和处理

大多数情况下,优化器都能找到正确的索引,但是当优化器选择索引不正确时,应该怎么办?

  • 采用 force index 强行选择一个索引。(不优雅)
  • 修改语句,引导 MySQL 使用我们期望的索引。
  • 新建一个更合适的索引或删掉误用的索引。