delete in子查询不走索引问题分析


Posted in MySQL onJuly 07, 2022

文章开篇前,先问大家一个问题:delete in子查询,是否会走索引呢?很多伙伴第一感觉就是:会走索引。最近我们有个生产问题,就跟它有关。本文将跟大家一起探讨这个问题,并附上优化方案。

delete in子查询不走索引问题分析

问题复现

MySQL版本是5.7,假设当前有两张表accountold_account,表结构如下:

CREATE TABLE `old_account` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
  `name` varchar(255) DEFAULT NULL COMMENT '账户名',
  `balance` int(11) DEFAULT NULL COMMENT '余额',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='老的账户表';

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
  `name` varchar(255) DEFAULT NULL COMMENT '账户名',
  `balance` int(11) DEFAULT NULL COMMENT '余额',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';

执行的SQL如下:

delete from account where name in (select name from old_account);

我们explain执行计划走一波,

delete in子查询不走索引问题分析

explain结果可以发现:先全表扫描 account,然后逐行执行子查询判断条件是否满足;显然,这个执行计划和我们预期不符合,因为并没有走索引

但是如果把delete换成select,就会走索引。如下:

delete in子查询不走索引问题分析

为什么select in子查询会走索引,delete in子查询却不会走索引呢?

原因分析

select in子查询语句跟delete in子查询语句的不同点到底在哪里呢?

我们执行以下SQL看看

explain select * from account where name in (select name from old_account);
show WARNINGS;

show WARNINGS 可以查看优化后,最终执行的sql

结果如下:

select `test2`.`account`.`id` AS `id`,`test2`.`account`.`name` AS `name`,`test2`.`account`.`balance` AS `balance`,`test2`.`account`.`create_time` AS `create_time`,`test2`.`account`.`update_time` AS `update_time` from `test2`.`account` 
semi join (`test2`.`old_account`)
where (`test2`.`account`.`name` = `test2`.`old_account`.`name`)

可以发现,实际执行的时候,MySQL对select in子查询做了优化,把子查询改成join的方式,所以可以走索引。但是很遗憾,对于delete in子查询,MySQL却没有对它做这个优化。

优化方案

那如何优化这个问题呢?通过上面的分析,显然可以把delete in子查询改为join的方式。我们改为join的方式后,再explain看下:

delete in子查询不走索引问题分析

可以发现,改用join的方式是可以走索引的,完美解决了这个问题。

实际上,对于update或者delete子查询的语句,MySQL官网也是推荐join的方式优化

delete in子查询不走索引问题分析

其实呢,给表加别名,也可以解决这个问题哦,如下:

explain delete a from account as a where a.name in (select name from old_account)

delete in子查询不走索引问题分析

为什么加个别名就可以走索引了呢?

what?为啥加个别名,delete in子查询又行了,又走索引了?

我们回过头来看看explain的执行计划,可以发现Extra那一栏,有个LooseScan

delete in子查询不走索引问题分析

LooseScan是什么呢? 其实它是一种策略,是semi join子查询的一种执行策略。

因为子查询改为join,是可以让delete in子查询走索引;加别名呢,会走LooseScan策略,而LooseScan策略,本质上就是semi join子查询的一种执行策略。

因此,加别名就可以让delete in子查询走索引啦!

总结

本博文分析了delete in子查询不走索引的原因,并附上解决方案。delete in在日常开发,是非常常见的,平时大家工作中,需要注意一下。同时呢,建议大家工作的时候,写SQL的时候,尽量养成一个好习惯,先用explain分析一下SQL,更多关于delete in子查询索引的资料请关注三水点靠木其它相关文章!


Tags in this post...

MySQL 相关文章推荐
mysql知识点整理
Apr 05 MySQL
MySQL入门命令之函数-单行函数-流程控制函数
Apr 05 MySQL
mysql优化
Apr 06 MySQL
探究Mysql模糊查询是否区分大小写
Jun 11 MySQL
分析mysql中一条SQL查询语句是如何执行的
Jun 21 MySQL
MySQL 聚合函数排序
Jul 16 MySQL
mysql 索引合并的使用
Aug 30 MySQL
mysql如何能有效防止删库跑路
Oct 05 MySQL
MySQL Server 层四个日志
Mar 31 MySQL
MySQL中EXPLAIN语句及用法
May 20 MySQL
mysql sql常用语句大全
Jun 21 MySQL
MySQL自定义函数及触发器
Aug 05 MySQL
MySQL提升大量数据查询效率的优化神器
mysql查看表结构的三种方法总结
Jul 07 #MySQL
MySQL中正则表达式(REGEXP)使用详解
MySQL实现字段分割一行转多行的示例代码
MySQL控制流函数(-if ,elseif,else,case...when)
Jul 07 #MySQL
mysql拆分字符串作为查询条件的示例代码
Jul 07 #MySQL
mysql全面解析json/数组
Jul 07 #MySQL
You might like
关于拼配咖啡,你要知道
2021/03/03 咖啡文化
PHP新手上路(三)
2006/10/09 PHP
关于session在PHP5的配置文件中的详细设置参数说明
2011/04/20 PHP
使用PHP编写发红包程序
2015/07/22 PHP
详解WordPress中简码格式标签编写的基本方法
2015/12/22 PHP
PHP查询附近的人及其距离的实现方法
2016/05/11 PHP
javascript实现的动态添加表单元素input,button等(appendChild)
2007/11/24 Javascript
jquery获取div距离窗口和父级dv的距离示例
2013/10/10 Javascript
JavaScript实现的购物车效果可以运用在好多地方
2014/05/09 Javascript
JS的location.href跳出框架打开新页面的方法
2014/09/04 Javascript
Thinkphp模板没有解析直接原样输出的解决方法
2014/10/31 Javascript
Javascript学习笔记之数组的构造函数
2014/11/23 Javascript
JS+CSS实现六级网站导航主菜单效果
2015/09/28 Javascript
JS hashMap实例详解
2016/05/26 Javascript
js判断空对象的实例(超简单)
2016/07/26 Javascript
jquery移除了live()、die(),新版事件绑定on()、off()的方法
2016/10/26 Javascript
Reactjs实现通用分页组件的实例代码
2017/01/19 Javascript
bootstrap精简教程_动力节点Java学院整理
2017/07/14 Javascript
JavaScript原型对象原理与应用分析
2018/12/27 Javascript
解决js中的setInterval清空定时器不管用问题
2020/11/17 Javascript
[01:23:59]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 VP vs Secret
2018/04/03 DOTA
python dict.get()和dict['key']的区别详解
2016/06/30 Python
python利用urllib和urllib2访问http的GET/POST详解
2017/09/27 Python
Python第三方Window模块文件的几种安装方法
2018/11/22 Python
win7下 python3.6 安装opencv 和 opencv-contrib-python解决 cv2.xfeatures2d.SIFT_create() 的问题
2019/10/24 Python
Django跨域资源共享问题(推荐)
2020/03/09 Python
python开发入门——列表生成式
2020/09/03 Python
澳大利亚购买最佳炊具品牌网站:Cookware Brands
2019/02/16 全球购物
2014标准社保办理委托书
2014/10/06 职场文书
个人政治思想总结
2015/03/05 职场文书
公司周年庆典致辞
2015/07/30 职场文书
写作技巧:如何撰写一份优秀的营销策划书
2019/08/13 职场文书
使用 CSS 轻松实现一些高频出现的奇形怪状按钮
2021/12/06 HTML / CSS
SQL Server查询某个字段在哪些表中存在
2022/03/03 SQL Server
Python中with上下文管理协议的作用及用法
2022/03/18 Python
戴尔Win11系统no bootable devices found解决教程
2022/09/23 数码科技