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 22 MySQL
MySQL数字类型自增的坑
May 07 MySQL
MySQL 8.0 之不可见列的基本操作
May 20 MySQL
浅谈mysql返回Boolean类型的几种情况
Jun 04 MySQL
浅谈MySQL user权限表
Jun 18 MySQL
MySQL图形化管理工具Navicat安装步骤
Dec 04 MySQL
mysql使用FIND_IN_SET和group_concat两个方法查询上下级机构
Apr 20 MySQL
mysql如何查询连续记录
May 11 MySQL
MySQL的prepare使用以及遇到的bug
May 11 MySQL
浅谈MySql update会锁定哪些范围的数据
Jun 25 MySQL
MySQL分布式恢复进阶
Jul 23 MySQL
SQLyog的下载、安装、破解、配置教程(MySQL可视化工具安装)
Sep 23 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生成二维码的两种方法(带logo图像)
2014/03/14 PHP
Yii2中datetime类的使用
2016/12/17 PHP
PHP单例模式与工厂模式详解
2017/08/29 PHP
PHP中abstract(抽象)、final(最终)和static(静态)原理与用法详解
2020/06/05 PHP
使用jQuery全局事件ajaxStart为特定请求实现提示效果的代码
2010/12/30 Javascript
yepnope.js使用详解及示例分享
2014/06/23 Javascript
js对象的复制继承实例
2015/01/10 Javascript
js实现类似于add(1)(2)(3)调用方式的方法
2015/03/04 Javascript
JS实现生成会变大变小的圆环实例
2015/08/05 Javascript
js多个物体运动功能实例分析
2016/12/20 Javascript
jquery pagination分页插件使用详解(后台struts2)
2017/01/22 Javascript
详解用node-images 打造简易图片服务器
2017/05/08 Javascript
vue实现图片加载完成前的loading组件方法
2018/02/05 Javascript
移动端吸顶fixbar的解决方案详解
2019/07/17 Javascript
VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析
2019/12/02 Javascript
JS关闭子窗口并且刷新上一个窗口的实现示例
2020/03/10 Javascript
javascript用defineProperty实现简单的双向绑定方法
2020/04/03 Javascript
[46:00]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第一局
2016/03/03 DOTA
[01:07:34]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第二场 1月9日
2021/03/11 DOTA
python使用7z解压软件备份文件脚本分享
2014/02/21 Python
在Python中使用base64模块处理字符编码的教程
2015/04/28 Python
Python中使用urllib2模块编写爬虫的简单上手示例
2016/01/20 Python
实例讲解Python中SocketServer模块处理网络请求的用法
2016/06/28 Python
Python实现计算圆周率π的值到任意位的方法示例
2018/05/08 Python
[原创]Python入门教程5. 字典基本操作【定义、运算、常用函数】
2018/11/01 Python
Python+opencv 实现图片文字的分割的方法示例
2019/07/04 Python
Python实现分数序列求和
2020/02/25 Python
python如何提升爬虫效率
2020/09/27 Python
python向企业微信发送文字和图片消息的示例
2020/09/28 Python
Autopep8的使用(python自动编排工具)
2021/03/02 Python
为什么要做架构设计
2015/07/08 面试题
大学毕业生文采飞扬的自我鉴定
2013/12/03 职场文书
乡镇干部党的群众路线教育实践活动个人对照检查材料
2014/09/24 职场文书
vue实现锚点定位功能
2021/06/29 Vue.js
mysq启动失败问题及场景分析
2021/07/15 MySQL
Python函数中apply、map、applymap的区别
2021/11/27 Python