10:MYSQL优化器选错索引问题

10:MYSQL优化器选错索引问题

MYSQL选错索引原因之一 可能是判断语句扫描行数时出现问题

MYSQL在真正开始执行语句前,根据索引的区分度来估算记录数,区分度就是索引上不同的值的比例,而索引上不同值的个数称为基数

MYSQL得到基数的方法:采样统计,InnoDB会默认选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数,变更数据行超过1/M时会自动触发重新做一次索引统计,但由于是采样统计,这个结果很容易不准

优化器还需要判断执行这个语句本身要扫描多少行

举个例子,我们先建一个简单的表,表里有 a、b 两个字段,并分别建上索引:

10:MYSQL优化器选错索引问题_第1张图片

然后,我们往表 t 中插入 10 万行记录,取值按整数递增,即:(1,1,1),(2,2,2),(3,3,3) 直 到 (100000,100000,100000)。

//首先建立索引A
select * from t where a between 10000 and 20000; /*Q1*/

select * from t force index(a) where a between 10000 and 20000;/*Q2*/

10:MYSQL优化器选错索引问题_第2张图片

上图是优化器预估的扫描行数,但Q1优化器选择了走扫描10万行的语句,也就是并没有走索引a

这是因为,如果使用索引 a,每次从索引 a 上拿到一个值,都要回到主键索引上查出整行数 据,这个代价优化器也要算进去的。 而如果选择扫描 10 万行,是直接在主键索引上扫描的,没有额外的代价。 优化器会估算这两个选择的代价,从结果看来,优化器认为直接扫描主键索引更快。当然, 从执行时间看来,这个选择并不是最优的。

analyze table t 命令,可以用来重新统计索引信息。我们来看一下执行效果。

10:MYSQL优化器选错索引问题_第3张图片

其实,如果只是索引统计不准确,通过 analyze 命令可以解决很多问题,但是前面我们说 了,优化器可不止是看扫描行数

依然是基于这个表 t,我们看看另外一个语句:

在这里插入图片描述
在这里插入图片描述

可以发现 , MySQL 又选错了索引,而原因是因为优化器认为使用索引 b 可以避免排序(b 本身是索引,已 经是有序的了,如果选择索引 b 的话,不需要再做排序,只需要遍历),所以即使扫描行 数多,也判定为代价更小。

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

你可能感兴趣的:(MySQL,mysql,数据库,java)