mysql之优化器选择索引

前言

之前文章,把索引和日志串起来介绍了一下,介绍了什么时候时候用普通索引,什么时候用唯一索引。还说明了,为什么要用普通索引,为什么要用唯一索引。和使用的原因。今天我们把索引和第一章介绍的mysql大致组成串联起来,来介绍下优化器的索引选择。

索引选择错误的几种情况

统计异常

首先创建一个表


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

然后插入10万条数据,从(1,1,1)到(100000,100000,100000),然后执行下面这个sql

select * from t where a between 10000 and 20000;

这个时候呢,优化器会选择那个索引呢。结果看下面
在这里插入图片描述
他会选择a索引。
但是同样的查询,如果是下面的这个查询过程
在这里插入图片描述
他会是什么结果呢。它会走主键索引进行全表扫描。那为什么放着索引a不走,非得走主键索引呢。有两个原因
1.主键索引和普通索引扫描行数相差不大得情况下,他会选择主键索引,这是因为走普通索引需要回表(这个之前得章节有介绍,这里不再介绍了)。优化器会认为,回表的时间会大于多扫描的那几行。
2.索引统计错误,就是比如现在这个,主键索引是100000多行,普通索引是30000多行,相差这么大。它为什么还要走主键索引呢,这个就是它在统计索引时出现了异常,可能统计普通索引a可能需要扫描9万多行,或者10万多行。这个时候就是第一种的情况了。
统计索引出现异常怎么办呢。有两种方案
1.analyze table t 命令,可以用来重新统计索引信息。
2.force index(a) 强行指定索引

排序导致的异常

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

看上面这个语句,走a的话只要扫面1000多行,走b的话需要扫面5000多行,正常来说应该是走a快,事实也是走a快,但是优化器却选择了走b,这个是为什么呢。首先这个表已经矫正过索引的信息了,不会出现统计异常的情况了。那是什么原因呢。
那是因为order by b,结果需要根据b排序,走索引b 的话不需要排序了,b直接是有序的。优化器认为排序时间会大于多扫描那些行数的时间。所以会选择走b。那有什么解决方案呢。
1.将sql的order by b改为 order by a,b,这样的话系统会认为a和b都需要排序,这样它就会选择扫描行数少的。
2.创建一个更好的索引,或者删除一些索引。比如上面这个就可以直接删除索引b,这样它就会走索引a了。
3.force index(a) 强行指定索引,上面统计异常也可以这么干。

select * from t force index(a) where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;

扫描行数数的统计

上面说了那么多,基本都是基于扫描行数为基准的,那么扫描行数是怎么统计的。首先,在开始扫描之前,优化器是不会知道,具体的扫描行数的。而是根据统计信息估算出扫描行数。统计信息又是什么呢。统计信息是一个索引的区分度,也就是一个索引上不同值得多少。而一个索引上不同值得个数,被称为统计基数。所以统计基数越大,也就是区分度越好。
那么怎么得到统计基数呢,首先一行一行扫描不现实,虽然精确,但是太耗费时间。所以mysql采用了采样统计得方式,因为mysql数据在磁盘中是以数据页得形式存储的。mysql会选择n个数据页,算出每个数据也的基数平均值,最后乘以这个索引的数据页数,得到这个索引的基数。而优化器就是根据这个基数进行索引选择的,虽然有一定的偏差,但是基本不会影响正确索引的选择。

总结

今天我们介绍了,一些常见的索引选择错误的情况,大致就两种。然后还介绍了每种的情况所对应的解决方案有哪些,方案很多,大家可以自信选择。比较通用的是指定索引,但是不见建议大家这么干。因为指标不治本,不太好。最后就是介绍优化器选择的关键,扫描行数的怕判定。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mark---小鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值