优化系列 | DELETE子查询改写优化
0、导读
有个采用子查询的DELETE执行得非常慢,改写成SELECT后执行却很快,最后把这个子查询DELETE改写成JOIN优化过程
1、问题描述
朋友遇到一个怪事,一个用子查询的DELETE,执行效率非常低。把DELETE改成SELECT后执行起来却很快,百思不得其解。
下面就是这个用了子查询的DELETE了:
[yejr@imysql.com]mydb > EXPLAIN delete from trade_info where id in (
select id from (
select a.id from trade_info a, order_info b, user c where
b.buyer = c.id and c.itv_account=’90000248′ and a.order_id = b.id) temp)\G

几个表的DDL是这样的:

上面这个SQL的执行耗时是:31.74秒
Query OK, 5 rows affected (31.74 sec)
如果我们把DELETE改写成SELECT的话,执行耗时仅是:0秒,来对比看下执行计划:
[yejr@imysql.com]mydb >EXPLAIN select id from trade_info where
id in (
select id from (
select a.id from trade_info a, order_info b, user c where
b.buyer = c.id and c.itv_account=’90000248′ and a.order_id = b.id) temp)\G

可以看到,trade_info 表从的全表扫描(type=ALL)变成了基于主键的等值查询(type=eq_ref),计划扫描数据量也从571万变成了1条,而且还可以避免回表,这2个SQL对比代价相差巨大。
2、优化思路
既然这个SQL把DELETE改成SELECT后执行效率就可以获得很大提升,除此外没特别区别,可能是查询优化器方面有些不足,导致无法直接优化,就得另想办法了。
我们的思路是把基于子查询的DELETE简化改写成多表JOIN后DELETE(一般来说,子查询效率比较低的话,可以考虑改写成JOIN),多表DELETE的语法课参考:https://dev.mysql.com/doc/refman/5.7/en/delete.html#idm140469624466800,例如这样的:
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
参照上面的形式,改写之后的SQL变成了下面这样:
DELETE trade_info
FROM
trade_info,
(
SELECT
a.id
FROM
trade_info a
JOIN order_info b ON a.order_id = b.id
JOIN user c ON b.buyer = c.id
WHERE
c.itv_account = ‘90000248’
) t2 where trade_info.id = t2.id;

可以看到新的SQL执行效率相对就高很多了,不需要再扫描571万条记录,执行耗时只需:0.01秒。
Query OK, 5 rows affected (0.01 sec)
3、其他建议
虽然MySQL 5.6及以上的版本对子查询做了优化,但从本案例的结果来看,在一些情况下还是不如意。
因此,如果发现有些子查询SQL效率比较差的话,可以尝试改写成JOIN形式,看看是否有所提升。此外,也要勇于怀疑查询优化器个别情况下存在不足,想办法绕过这些坑。
优化系列 | DELETE子查询改写优化的更多相关文章
- MySQL 子查询(四)子查询的优化、将子查询重写为连接
MySQL 5.7 ref ——13.2.10.10优化子查询 十.子查询的优化 开发正在进行中,因此从长远来看,没有什么优化建议是可靠的.以下列表提供了一些您可能想要使用的有趣技巧.See also ...
- paip.sql索引优化----join 代替子查询法
paip.sql索引优化----join 代替子查询法 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.n ...
- MySQL子查询的优化
本文基于MySQL5.7.19测试 创建四张表,pt1.pt2表加上主键 mysql> create table t1 (a1 int, b1 int); mysql> create ta ...
- 【SqlServer系列】子查询
1 概述 1.1 已发布[SqlServer系列]文章 [SqlServer系列]SQLSERVER安装教程 [SqlServer系列]数据库三大范式 [SqlServer系列]表单查询 [Sq ...
- [慢查优化]慎用MySQL子查询,尤其是看到DEPENDENT SUBQUERY标记时
案例梳理时间:2013-9-25 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助, ...
- mysql update/delete in 子查询改写
#子查询(不支持) limit ,); #改写 limit ,) t ; #子查询(不支持) delete from `user` where id in ( ) ); #改写 delete from ...
- mysql优化---in型子查询,exists子查询,from 型子查询
in型子查询引出的陷阱:(扫更少的行,不要临时表,不要文件排序就快) 题: 在ecshop商城表中,查询6号栏目的商品, (注,6号是一个大栏目) 最直观的: mysql); 误区: 给我们的感觉是, ...
- Mysql查询优化器之关于子查询的优化
下面这些sql都含有子查询: mysql> select * from t1 where a in (select a from t2); mysql> select * from (se ...
- mysql5.6子查询的优化
https://dev.mysql.com/doc/refman/5.6/en/subquery-optimization.html Semi-join in MySQL 5.6 MySQL 5. ...
随机推荐
- map集合遍历的五种方法
package com.jackey.topic; import java.util.ArrayList;import java.util.HashMap;import java.util.Itera ...
- HTML 14 JS事件
一 :什么是事件 发生的某一件事:触发特定的条件,完成某一项功能 二:学习的目的 在特定的条件下,完成特定的功能 条件满足的情况下,系统会自动执行 ( 回调 ) 绑定的方法 学习要点: 1.事件的两种 ...
- [Swift]LeetCode1064. 不动点 | Fixed Point
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- centOS 7.4 安装配置jdk1.8
按以下步骤安装 JDK. 1.新建一个目录: mkdir /usr/java 2.通过XShell 上传本地安装包或者通过命令下载在线安装包 wget http://mirrors.linuxeye. ...
- 金立 M6 (GN8003) 解锁 BootLoader 进入第三方 recovery 刷机 ROOT
首先下载好工具:http://url.cn/5EILbQn 备用连接 :http://pan.baidu.com/s/1c28j7k0 本篇教程教你如何傻瓜式解锁BootLoader并刷入recove ...
- 【Linux】连接CRT
linux中出现crt连接不上多数是ip地址设置不正确. window中命令行界面(cmd进入),输入ipconfig,查看虚拟机的ip. 打开linux终端,命令行下输入:ifconfig eth0 ...
- macOS下登录store或者xcode等应用时提示【this action could not be completed】
sudo mkdir -p /Users/Shared sudo chown root:wheel /Users/Shared sudo chmod -R 1777 /Users/Shared === ...
- Embedded之Stack之二
1 Function Programming languages make functions easy to maintain and write by giving each function i ...
- OpenCV边缘检测的详细参数调节
1. findCountours 转载于http://blog.sina.com.cn/s/blog_7155fb1a0101a90h.html findContours函数,这个函数的原型为: &l ...
- c#同步锁Monitor.Enter(T)
protected static object MObjLock = new object();//同步锁 public string GetData(int mId) { Monitor.Enter ...