美文网首页
为何MySQL会选错索引

为何MySQL会选错索引

作者: 蓝洛333 | 来源:发表于2021-03-13 11:07 被阅读0次

在实际的生产环境中,给MySQL的字段加索引让查询的效率更高,我们往往会给MySQL的表字段加索引。MySQL具体选择哪个索引是有MySQL的优化器决定的。不知道小伙伴们有没有遇到一种情况,就是实际的查询中速度应该很快才对的,但因为MySQL选错的索引,导致查询的速度变慢了。至此,我们来看一下下面的例子。

牛刀小试

首先,我们简单创建一张表,表里面有两个字段,分别是a和b,并且我们给a和b加上索引,SQL语句执行如下:

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `a` (`a`),
 KEY `b` (`b`)
) ENGINE=InnoDB

接下来我们使用存储过程或者是跑代码的形式往表里插入10万条数据,此处使用存储过程,代码如下所示:

delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t values(i, i, i);
set i=i+1;
end while;
end;;
delimiter ;
call idata();

然后我们使用执行计划运行一条简单的SQL语句,代码如下:

explain select * from t where a between 15000 and 20000

运行之后,如下所示:

为何MySQL会选错索引

可以看到,执行这条语句的时候,MySQL使用了a上面的索引,只扫描(row)了5000条记录。想必这样的结果大家都是可以猜到的。

在这里,也许小伙伴们就会有疑问了,MySQL是怎么计算出row数的?其实,MySQL大部分时候并不能很精准的统计出这个row数,MySQL在这里主要采用的方式是抽样的方式进行计算的,即 row数 = (N个数据页不同值个数平均值) ×索引 页数。一个索引上不同的值越多,这个索引的区分度就越好。而一个索引上的不同值的个数就被称为基数。所以,row数其实严格意义上来说是不会100%精准的。

那么,我们再执行如下的SQL语句,看结果如何,代码如下:

explain select * from t where a between 5000 and 15000 and b between 10000 and 100000 order by b limit 100

其结果如下所示:

为何MySQL会选错索引

从这次的分析可以看出,MySQL最后选择了b索引,扫描了50233行数据。从这结果来看,我们不难猜出MySQL选错索引了。在MySQL中,order by 和 limit 结合使用,如果where 字段,order by字段上都有索引,那么有limit时索引会使用order by字段所在的索引,没有limit会使用where 条件的索引。造成这种原因主要是b字段上面存在索引,所以MySQL的优化器认为使用b索引可以避免排序,直接遍历然后取出相应的limit的条数就可以了,所以这里MySQL扫描的行数虽然多,但仍然被优化器认为是代价最小的。

在这里的话,由于where条件中a的范围要比b的要小,所以,这里如果使用a作为索引的话,肯定查询的速度会比b的快,所以,我们执行如下的SQL语句,进行分析下:

explain select * from t force index(a) where a between 5000 and 15000 and b between 10000 and 100000 order by b limit 100;

其结果如下图所示:

为何MySQL会选错索引

从两图可以看出,使用a索引所消耗的时间要比b索引所消耗的时间少。

优化

其实,MySQL在查询的过程中,大部分时候索引的选择都是正确的,只有偶尔会遇到以上的情况,那么,如何解决以上问题的发生呢?

1. 使用force index的形式来矫正MySQL索引的选择。不过,挺多程序员实际中并不会使用强制索引,主要是因为如果索引改了名字,这个语句也得改,显得很麻烦。而且如果以后迁移到别的数据库的话,这个语法还可能会不兼容

2. 修改MySQL语句,引导优化器去选择索引。例如在上面的例子中,可以把 order by b limit 100 改成 order by b,a limit 100,这样就意味着两个索引都要排序,优化器就会选择row行数比较少的索引。

3. 删除无效的索引,或者新建更优的索引。

相关文章

  • 丁奇-MySQL实战读书笔记10

    MySQL为什么有时候会选错索引? 1:MySQL选错索引,啥意思? 我们认为使用K索引检索的速度会更快的,但是M...

  • 为何MySQL会选错索引

    在实际的生产环境中,给MySQL的字段加索引让查询的效率更高,我们往往会给MySQL的表字段加索引。MySQL具体...

  • mysql选错索引

    为什么会出现选错索引 优化器会判定当前执行的最优方式,主要包括考虑扫描的行数、是否使用临时表、是否需要排序等; 优...

  • 10 - MySQL选错索引

    关键字 索引选择 0.错误情况 首先,建立一个简单的表,表中有 a、b 两个字段,并且分别建立了索引: 然后,我们...

  • mysql听讲(十)

    本文源自 极客网站 的某知名大佬讲mysql,整理一下心得和重点。 第10节 mysql为什么会选错索引 mys...

  • mysql竟然也会选错索引

    我们都知道一张表可以建很多索引,我们在执行一次查询时并没有执行使用哪个索引,是谁在帮助我们决定使用什么索引?是my...

  • 案例分析之mysql选错索引

    前言案例取自极客时间《mysql45讲》 案例 模拟执行器分析查询语句 场景复现 奇了怪了,此时没用索引,进行了全...

  • MySQL索引及查询优化书目录

    MySQL索引的原理之索引目的 MySQL索引的原理之索引原理 MySQL索引的原理之索引的类型 MySQL索引的...

  • 高性能的索引策略

    MySQL查询基础-查询执行过程 MySQL聚簇索引 MySQL覆盖索引 MySQL索引扫描排序 MySQL冗余和...

  • MySQL索引的使用

    MySQL索引 MySQL索引可以快速提高MySQL的检索速度。索引分单列索引和组合索引单列索引:即一个索引只包含...

网友评论

      本文标题:为何MySQL会选错索引

      本文链接:https://www.haomeiwen.com/subject/pkhxcltx.html