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 查询速度慢的原因
May 25 MySQL
MySQL系列之十三 MySQL的复制
Jul 02 MySQL
MySQL系列之二 多实例配置
Jul 02 MySQL
MySQL数据库超时设置配置的方法实例
Oct 15 MySQL
SQL实战演练之网上商城数据库商品类别数据操作
Oct 24 MySQL
防止web项目中的SQL注入
Dec 06 MySQL
详解MySQL中timestamp和datetime时区问题导致做DTS遇到的坑
Dec 06 MySQL
你真的会用Mysql的explain吗
Mar 31 MySQL
MySQL数据库查询进阶之多表查询详解
Apr 08 MySQL
Windows下载并安装MySQL8.0.x 版本的完整教程
Apr 10 MySQL
MySQL库表太大怎么办? 数据库分库分表项目实践
Apr 11 MySQL
Mysql将字符串按照指定字符分割的正确方法
May 30 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
浅析php中jsonp的跨域实例
2013/06/21 PHP
参考:关于Javascript中实现暂停的几篇文章
2007/03/04 Javascript
js检测客户端不是firefox则提示下载
2007/04/07 Javascript
JavaScript的Cookies
2008/01/16 Javascript
采用call方式实现js继承
2014/05/20 Javascript
ECMAScript5中的对象存取器属性:getter和setter介绍
2014/12/08 Javascript
浅谈JavaScript字符串与数组
2015/06/03 Javascript
jQuery插件实现可输入和自动匹配的下拉框
2016/10/24 Javascript
jQuery中table数据的值拷贝和拆分
2017/03/19 Javascript
微信小程序 Buffer缓冲区的详解
2017/07/06 Javascript
nodejs中Express与Koa2对比分析
2018/02/06 NodeJs
nodejs+express搭建多人聊天室步骤
2018/02/12 NodeJs
使用weixin-java-tools完成微信授权登录、微信支付的示例
2018/09/26 Javascript
Vue传参一箩筐(页面、组件)
2019/04/04 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
2019/06/12 Javascript
深入了解JavaScript 防抖和节流
2019/09/12 Javascript
Vue自定义全局弹窗组件操作
2020/08/11 Javascript
在Python的Flask框架下使用sqlalchemy库的简单教程
2015/04/09 Python
python通过post提交数据的方法
2015/05/06 Python
Python实现七彩蟒蛇绘制实例代码
2018/01/16 Python
python实现图片文件批量重命名
2020/03/23 Python
python 使用正则表达式按照多个空格分割字符的实例
2018/12/20 Python
Python Django2 model 查询介绍(条件、范围、模糊查询)
2020/03/16 Python
图解CSS3制作圆环形进度条的实例教程
2016/05/26 HTML / CSS
美国滑雪和滑雪板商店:Buckman
2018/03/03 全球购物
eBay英国购物网站:eBay.co.uk
2019/06/19 全球购物
介绍一些UNIX常用简单命令
2014/11/11 面试题
护理专业毕业生自我鉴定
2013/10/08 职场文书
公司财务流程之主管工作流程
2014/03/03 职场文书
中秋寄语大全
2014/04/11 职场文书
会计工作总结范文2014
2014/12/23 职场文书
未婚证明格式
2015/06/15 职场文书
七夕情人节问候语
2015/11/11 职场文书
Python 中random 库的详细使用
2021/06/03 Python
为什么代码规范要求SQL语句不要过多的join
2021/06/23 MySQL
Python中如何处理常见报错
2022/01/18 Python