mysql为什么会选错索引?

2021/7/8 2:05:49

本文主要是介绍mysql为什么会选错索引?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

数据库为什么会选错索引?

mysql可能不走索引
比如mysql判断是否走 c 字段索引时,系统会预测走 c 字段索引大概需要扫描多少行。如果预测到要扫描的行数很多,它可能就不走索引而直接扫描全表了。

系统是怎么预测的呢?
系统是通过索引的区分度来判断的,我们也把区分度称之为基数,即区分度越高,基数越大,
一个索引上不同的值越多,意味着出现相同数值的索引越少,意味着利用索引查询的次数越少。
所以,一个索引的基数越大,意味着走索引查询越有优势。
即基数越大越好,性别由于基数太小就不适合建索引。

msyql怎么知道这个索引的基数呢?
系统当然是不会遍历全部行来获得一个索引的基数的,代价太大了,索引系统是通过遍历部分行,通过采样的方式,来预测索引的基数的。

重点来了,因为是采样,所以必然存在误差,比如c 这个索引的基数实际上是很大的,但是采样的时候,却很不幸,把这个索引的基数预测成很小。然后就误以为索引的基数很小。所以系统就不走 c 索引了,直接走全部扫描了。于是就选错了索引。

结论:由于统计的失误,导致系统没有走索引,而是走了全表扫描,而这,也是导致我们 SQL 语句执行的很慢的原因。

系统判断是否走索引,扫描行数的预测其实只是原因之一,临时表、是否需要排序等也是会影响系统的选择的。

举例

比如下面的sql语句:

mysql> explain select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;

用索引a明显快于索引b,因为a索引只需要扫描1000行,而b索引要扫描5000行。
但是mysql实际执行时会选择索引b。因为它认为使用索引 b 可以避免排序(order by b),所以即使扫描行数多,也判定为代价更小。

选错索引该怎么办?

2、考虑修改语句,引导 MySQL 使用我们期望的索引。

比如,在这个例子里,显然把“order by b limit 1” 改成 “order by b,a limit 1” ,语义的逻辑是相同的。
现在 order by b,a 这种写法,要求按照 b,a 排序,就意味着使用这两个索引都需要排序。因此,扫描行数成了影响决策的主要条件,于是此时优化器就会选择只需要扫描 1000 行的索引 a。

当然,这种修改并不是通用的优化手段,只是刚好在这个语句里面有 limit 1,因此如果有满足条件的记录, order by b limit 1 和 order by b,a limit 1 都会返回 b 是最小的那一行,逻辑上一致,才可以这么做。

3、删掉误用的索引
将b索引删掉即可

1、采用 force index 强行帮mysql选择正确的索引。
在这里插入图片描述

MySQL 会根据词法解析的结果分析出可能可以使用的索引作为候选项,然后在候选列表中依次判断每个索引需要扫描多少行。如果 force index 指定的索引在候选索引列表中,就直接选择这个索引,不再评估其他索引的执行代价。

force index用的不多,因为选错索引的情况还是比较少出现的,所以开发的时候通常不会先写上 force index。而是等到线上出现问题的时候,你才会再去修改 SQL 语句、加上 force index。但是修改之后还要测试和发布,对于生产系统来说,这个过程不够敏捷。



这篇关于mysql为什么会选错索引?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程