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 26 MySQL
SQL注入的实现以及防范示例详解
Jun 02 MySQL
MySQL快速插入一亿测试数据
Jun 23 MySQL
MySQL Shell import_table数据导入的实现
Aug 07 MySQL
详细聊聊关于Mysql联合查询的那些事儿
Oct 24 MySQL
MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
Apr 09 MySQL
mysql使用 not int 子查询隐含陷阱
Apr 12 MySQL
mysql 8.0.27 绿色解压版安装教程及配置方法
Apr 20 MySQL
Mysql InnoDB 的内存逻辑架构
May 06 MySQL
MySQL数据库安装方法与图形化管理工具介绍
May 30 MySQL
mysql拆分字符串作为查询条件的示例代码
Jul 07 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
PHP基于Redis消息队列实现发布微博的方法
2017/05/03 PHP
postman的安装与使用方法(模拟Get和Post请求)
2018/08/06 PHP
PHP用swoole+websocket和redis实现web一对一聊天
2019/11/05 PHP
jQuery AnythingSlider滑动效果插件
2010/02/07 Javascript
JS判断元素为数字的奇异写法分享
2012/08/01 Javascript
利用js动态添加删除table行的示例代码
2013/12/16 Javascript
javaScript使用EL表达式的几种方式
2014/05/27 Javascript
jquery实现动态改变div宽度和高度
2015/05/08 Javascript
深入分析JSON编码格式提交表单数据
2015/06/25 Javascript
Bootstrap 布局组件(全)
2016/07/18 Javascript
JS组件系列之使用HTML标签的data属性初始化JS组件
2016/09/14 Javascript
JavaScript cookie详解及简单实例应用
2016/12/31 Javascript
关于Mac下安装nodejs、npm和cnpm的教程
2018/04/11 NodeJs
vue动态设置img的src路径实例
2018/09/18 Javascript
vue操作动画的记录animate.css实例代码
2019/04/26 Javascript
浅入深出Vue之组件使用
2019/07/11 Javascript
详解JWT token心得与使用实例
2019/08/02 Javascript
Vue(定时器)解决mounted不能获取到data中的数据问题
2020/07/30 Javascript
js观察者模式的弹幕案例
2020/11/23 Javascript
python使用socket远程连接错误处理方法
2015/04/29 Python
python通过openpyxl生成Excel文件的方法
2015/05/12 Python
python 借助numpy保存数据为csv格式的实现方法
2018/07/04 Python
Python中的CSV文件使用"with"语句的方式详解
2018/10/16 Python
python中metaclass原理与用法详解
2019/06/25 Python
Django框架配置mysql数据库实现过程
2020/04/22 Python
python中怎么表示空值
2020/06/19 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
2020/12/08 Python
HTML5打开本地app应用的方法
2016/03/31 HTML / CSS
高考自主招生自荐信
2013/10/20 职场文书
中式结婚主持词
2014/03/14 职场文书
大学共青团员个人自我评价
2014/04/16 职场文书
幼儿园教师师德表现自我评价
2015/03/05 职场文书
圣诞晚会主持词
2015/07/01 职场文书
导游词书写之黄山
2019/08/06 职场文书
SQL Server中常用截取字符串函数介绍
2022/03/16 SQL Server
vue cli4中mockjs在dev环境和build环境的配置详情
2022/04/06 Vue.js