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 update set 和 and的区别
May 08 MySQL
超详细教你怎么升级Mysql的版本
May 19 MySQL
为什么代码规范要求SQL语句不要过多的join
Jun 23 MySQL
SQL实现LeetCode(196.删除重复邮箱)
Aug 07 MySQL
MySQL中几种插入和批量语句实例详解
Sep 14 MySQL
详解MySql中InnoDB存储引擎中的各种锁
Feb 12 MySQL
Pycharm远程调试和MySQL数据库授权问题
Mar 18 MySQL
分享几个简单MySQL优化小妙招
Mar 31 MySQL
为什么MySQL不建议使用SELECT *
Apr 03 MySQL
MySQL中LAG()函数和LEAD()函数的使用
Aug 14 MySQL
MySQL常用慢查询分析工具详解
Aug 14 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
浅析使用Turck-mmcache编译来加速、优化PHP代码
2013/06/20 PHP
PHP正则表达式替换站点关键字链接后空白的解决方法
2014/09/16 PHP
php树型类实例
2014/12/05 PHP
php简单实现多字节字符串翻转的方法
2015/03/31 PHP
php实现产品加入购物车功能(1)
2020/07/23 PHP
超简单JS二级、多级联动的简单实例
2014/02/18 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
2014/08/14 Javascript
JavaScript中setUTCMilliseconds()方法的使用详解
2015/06/12 Javascript
在for循环中length值是否需要缓存
2015/07/27 Javascript
微信小程序 picker-view 组件详解及简单实例
2017/01/10 Javascript
详解vue中使用express+fetch获取本地json文件
2017/10/10 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
2018/07/03 Javascript
JavaScript构造函数原理及实现流程解析
2020/11/19 Javascript
Javascript 模拟mvc实现点餐程序案例详解
2020/12/24 Javascript
python list转dict示例分享
2014/01/28 Python
Python中的pprint折腾记
2015/01/21 Python
Python中的进程分支fork和exec详解
2015/04/11 Python
Python实现股市信息下载的方法
2015/06/15 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
2018/11/07 Python
python代码 输入数字使其反向输出的方法
2018/12/22 Python
python进程和线程用法知识点总结
2019/05/28 Python
Pytorch实现基于CharRNN的文本分类与生成示例
2020/01/08 Python
Python拼接字符串的7种方式详解
2020/03/19 Python
浅谈SciPy中的optimize.minimize实现受限优化问题
2020/02/29 Python
BISSELL官网:北美吸尘器第一品牌
2019/03/14 全球购物
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
.NET现在共支持多少种语言
2014/02/26 面试题
人力资源管理专业自荐书范文
2014/02/10 职场文书
优秀安全员事迹材料
2014/05/11 职场文书
党的群众路线对照检查材料思想汇报(学校)
2014/10/04 职场文书
2016年9月份红领巾广播稿
2015/12/21 职场文书
2016年度农村党员干部主题教育活动总结
2016/04/06 职场文书
导游词之河北野三坡
2019/12/11 职场文书
SQL Server中使用判断语句(IF ELSE/CASE WHEN )案例
2021/07/07 SQL Server
详细聊聊MySQL中慢SQL优化的方向
2021/08/30 MySQL
vue组件冲突之引用另一个组件出现组件不显示的问题
2022/04/13 Vue.js