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 相关文章推荐
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
May 06 MySQL
MySQL EXPLAIN输出列的详细解释
May 12 MySQL
IDEA 链接Mysql数据库并执行查询操作的完整代码
May 20 MySQL
mysql在项目中怎么选事务隔离级别
May 25 MySQL
详解MySQL中的主键与事务
May 27 MySQL
MySQL系列之八 MySQL服务器变量
Jul 02 MySQL
SQL实现LeetCode(196.删除重复邮箱)
Aug 07 MySQL
浅谈mysql哪些情况会导致索引失效
Nov 20 MySQL
解决MySQL添加新用户-ERROR 1045 (28000)的问题
Mar 03 MySQL
MySQL数据库如何给表设置约束详解
Mar 13 MySQL
Mysql排查分析慢sql之explain实战案例
Apr 19 MySQL
MySQL外键约束(Foreign Key)案例详解
Jun 28 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
WordPress中用于获取搜索表单的PHP函数使用解析
2016/01/05 PHP
详解PHP安装mysql.so扩展的方法
2016/12/31 PHP
php提交表单时保留多个空格及换行的文本样式的方法
2017/06/20 PHP
JXTree对象,读取外部xml文件数据,生成树的函数
2007/04/02 Javascript
海量经典的jQuery插件集合
2010/01/12 Javascript
JavaScript的模块化:封装(闭包),继承(原型) 介绍
2013/07/22 Javascript
jquery右下角弹出提示框示例代码
2013/10/08 Javascript
JS判断客户端是手机还是PC的2个代码
2014/04/12 Javascript
RequireJS入门一之实现第一个例子
2015/09/30 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
JS中BOM相关知识点总结(必看篇)
2016/11/22 Javascript
jQuery中用on绑定事件时需注意的事项
2017/03/19 Javascript
JavaScript数组去重的多种方法(四种)
2017/09/19 Javascript
Javascript刷新页面的实例
2017/09/23 Javascript
vue使用ElementUI时导航栏默认展开功能的实现
2018/07/04 Javascript
Javascript Web Worker使用过程解析
2020/03/16 Javascript
[06:15]2016国际邀请赛中国区预选赛单车采访:我顶WINGS
2016/06/27 DOTA
[01:15:00]LGD vs Mineski Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
python线程、进程和协程详解
2016/07/19 Python
基于python爬虫数据处理(详解)
2017/06/10 Python
Python使用文件锁实现进程间同步功能【基于fcntl模块】
2017/10/16 Python
python做量化投资系列之比特币初始配置
2018/01/23 Python
Django学习笔记之为Model添加Action
2019/04/30 Python
Python pip 安装与使用(安装、更新、删除)
2019/10/06 Python
python子线程退出及线程退出控制的代码
2019/10/16 Python
Python变量作用域LEGB用法解析
2020/02/04 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
2020/04/23 Python
Django前后端分离csrf token获取方式
2020/12/25 Python
Melijoe时尚童装德国官网:Melijoe德国
2016/09/03 全球购物
彼得罗夫美国官网:Peter Thomas Roth美国(青瓜面膜)
2017/11/05 全球购物
商务英语本科生的自我评价分享
2013/11/15 职场文书
建筑装饰学院室内设计专业个人自我评价
2013/12/07 职场文书
2015年度个人思想工作总结
2015/04/08 职场文书
2015银行年终工作总结范文
2015/05/26 职场文书
2016特色励志班级口号
2015/12/24 职场文书
党校培训学习心得体会
2016/01/06 职场文书