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 使用SQL语句修改表名的实现
Apr 07 MySQL
MySQL kill不掉线程的原因
May 07 MySQL
MySQL 逻辑备份与恢复测试的相关总结
May 14 MySQL
详解MySQL连接挂死的原因
May 18 MySQL
my.ini优化mysql数据库性能的十个参数(推荐)
May 26 MySQL
mysql 如何获取两个集合的交集/差集/并集
Jun 08 MySQL
MySQL中存储时间的最佳实践指南
Jul 01 MySQL
MyBatis 动态SQL全面详解
Oct 05 MySQL
mysql5.6主从搭建以及不同步问题详解
Dec 04 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
如何创建一个创建MySQL数据库中的datetime类型
Mar 21 MySQL
Mysql使用全文索引(FullText index)的实例代码
Apr 03 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
libmysql.dll与php.ini是否真的要拷贝到c:\windows目录下呢
2010/03/15 PHP
Symfony页面的基本创建实例详解
2015/01/26 PHP
CodeIgniter与PHP5.6的兼容问题
2015/07/16 PHP
php视频拍照上传头像功能实现代码分享
2015/10/08 PHP
ExtJs中gridpanel分组后组名排序实例代码
2013/12/02 Javascript
快速解决jquery之get缓存问题的最简单方法介绍
2013/12/19 Javascript
Javascript玩转继承(三)
2014/05/08 Javascript
JavaScript设计模式之工厂方法模式介绍
2014/12/28 Javascript
JavaScript获取网页表单提交方式的方法
2015/04/02 Javascript
javascript遇到html5的一些表单属性
2015/07/05 Javascript
JS实现CheckBox复选框全选、不选或全不选功能
2020/07/28 Javascript
提高Web性能的前端优化技巧总结
2017/02/27 Javascript
浅谈Emergence.js 检测元素可见性的 js 插件
2017/11/18 Javascript
使用selenium抓取淘宝的商品信息实例
2018/02/06 Javascript
vue2.0 computed 计算list循环后累加值的实例
2018/03/07 Javascript
Vue+Mock.js模拟登录和表格的增删改查功能
2018/07/26 Javascript
JS document form表单元素操作完整示例
2020/01/13 Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
2020/04/07 Javascript
[02:30]DOTA2英雄基础教程 暗影恶魔
2013/12/17 DOTA
对Python进行数据分析_关于Package的安装问题
2017/05/22 Python
python 3.6 tkinter+urllib+json实现火车车次信息查询功能
2017/12/20 Python
Python中循环后使用list.append()数据被覆盖问题的解决
2018/07/01 Python
python排序函数sort()与sorted()的区别
2018/09/18 Python
对numpy中向量式三目运算符详解
2018/10/31 Python
Python使用正则表达式分割字符串的实现方法
2019/07/16 Python
python socket 聊天室实例代码详解
2019/11/14 Python
Python闭包及装饰器运行原理解析
2020/06/17 Python
纯CSS3打造动感漂亮时尚的扇形菜单
2014/03/18 HTML / CSS
eBay奥地利站:eBay.at
2019/07/24 全球购物
如何判断计算机可能已经中马
2013/03/22 面试题
英语系本科生个人求职信
2013/09/21 职场文书
批评与自我批评发言稿
2014/10/15 职场文书
党组织领导班子整改方案
2014/10/25 职场文书
工程安全生产协议书
2014/11/21 职场文书
2015年采购部工作总结
2015/04/23 职场文书
导游词之平津战役纪念馆
2019/11/04 职场文书