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

一、引人入胜的问题

不知道你有没有碰到过这种情况,一条本来可以执行得很快的语句,却由于 MySQL 选错了索引,而导致执行速度变得很慢?
PS:如果这里回答没有遇见过,那也正常,毕竟刚看到这里我也没遇见过,打工人何必难为打工人~

我们先来创建一个表,看如何复现这个问题,过程如下⬇️

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;

然后,我们往表 t 中插入 10 万行记录,取值按整数递增,即:(1,1,1),(2,2,2),(3,3,3) 直到 (100000,100000,100000)。
PS:别问我如何插入?两种方式:1,撸代码。2,存储过程。

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();

–据说这个存储过程需要,编辑 my.conf将thread_stack 改为256k才能执行这个存储过程, 再重启 mysql。

分析如下SQL会走a索引?
mysql> select * from t where a between 10000 and 20000;
explain结果:
在这里插入图片描述
这条查询语句的执行也确实符合预期,key 这个字段值是’a’,表示优化器选择了索引 a。
PS:如果仅仅只是这样就完了么,肯定不是,我们接下来才是要放大招了。
在我们已经准备好的包含了 10 万行数据的表上,我们再做如下操作。
session A 的操作开启了一个事务。随后,session B 把数据都删除后,又调用了 idata 这个存储过程,插入了 10 万行数据。
🏁:为了说明优化器选择的结果是否正确,我增加了一个对照,即:使用 force index(a) 来让优化器强制使用索引 a(这部分内容,我还会在这篇文章的后半部分中提到)。
SQL如下:
set long_query_time=0;
// 将慢查询日志的阈值设置为 0表示这个线程接下来的语句都会被记录入慢查询日志中
select * from t where a between 10000 and 20000; /Q1/
select * from t force index(a) where a between 10000 and 20000;/Q2/

此时 此时 此时 执行结构
在这里插入图片描述
现象:Q1 扫描了 10 万行,显然是走了全表扫描,执行时间是 40 毫秒。Q2 扫描了 10001 行,执行了 21 毫秒

这个例子对应的是我们平常不断地删除历史数据和新增数据的场景。这时,MySQL 竟然会选错索引,是不是有点奇怪呢?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值