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
MySQL 数据类型选择原则
May 27 MySQL
mysql中between的边界,范围说明
Jun 08 MySQL
浅谈MySQL 亿级数据分页的优化
Jun 15 MySQL
mysql left join快速转inner join的过程
Jun 30 MySQL
MySQL系列之九 mysql查询缓存及索引
Jul 02 MySQL
mysql 直接拷贝data 目录下文件还原数据的实现
Jul 25 MySQL
MySQL中连接查询和子查询的问题
Sep 04 MySQL
Linux7.6二进制安装Mysql8.0.27详细操作步骤
Nov 27 MySQL
MySQL读取JSON转换的方式
Mar 18 MySQL
Nebula Graph解决风控业务实践
Mar 31 MySQL
了解MySQL查询语句执行过程(5大组件)
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
ecshop 订单确认中显示省市地址信息的方法
2010/03/15 PHP
PHP中计算字符串相似度的函数代码
2012/12/29 PHP
微信JSSDK上传图片
2015/08/23 Javascript
JavaScript使用简单正则表达式的数据验证功能示例
2017/01/13 Javascript
Nodejs实现短信验证码功能
2017/02/09 NodeJs
vue学习笔记之vue1.0和vue2.0的区别介绍
2017/05/17 Javascript
vue.js 获取当前自定义属性值
2017/06/01 Javascript
使用Require.js封装原生js轮播图的实现代码
2017/06/15 Javascript
10个最优秀的Node.js MVC框架
2017/08/24 Javascript
vue js秒转天数小时分钟秒的实例代码
2018/08/08 Javascript
详解微信小程序缓存--缓存时效性
2019/05/02 Javascript
Python中的自定义函数学习笔记
2014/09/23 Python
python字典序问题实例
2014/09/26 Python
Python 多核并行计算的示例代码
2017/11/07 Python
numpy中以文本的方式存储以及读取数据方法
2018/06/04 Python
详解关于Django中ORM数据库迁移的配置
2018/10/08 Python
使用python 打开文件并做匹配处理的实例
2019/01/02 Python
使用keras和tensorflow保存为可部署的pb格式
2020/05/25 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
Pytorch之扩充tensor的操作
2021/03/04 Python
css3 响应式媒体查询的示例代码
2019/09/25 HTML / CSS
西班牙三叶草药房:Farmacias Trébol
2019/05/03 全球购物
Agoda中文官网:安可达(低价预订全球酒店)
2021/01/18 全球购物
3个CCIE对一个工程师的面试题
2012/05/06 面试题
先进事迹报告会主持词
2014/04/02 职场文书
公司门卫工作职责
2014/06/28 职场文书
体育课外活动总结
2014/07/08 职场文书
奉献爱心演讲稿
2014/09/04 职场文书
2014最新开业庆典策划方案(5篇)
2014/09/15 职场文书
岗位竞聘报告范文
2014/11/06 职场文书
办公楼租房协议书范本
2014/11/25 职场文书
爱国影片观后感
2015/06/18 职场文书
奠基仪式致辞
2015/07/30 职场文书
交通事故协议书范本
2016/03/19 职场文书
用python基于appium模块开发一个自动收取能量的小助手
2021/09/25 Python
vue 自定义组件添加原生事件
2022/04/21 Vue.js