mysql优化系列 DELETE子查询改写优化

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形式,看看是否有所提升。此外,也要勇于怀疑查询优化器个别情况下存在不足,想办法绕过这些坑。

(0)

相关推荐

  • mysql优化系列 DELETE子查询改写优化

    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

  • mysql详细分析讲解子查询的使用

    出现在其他语句中的 select 语句,称为子查询或内查询:外部的查询语句,称为主查询或 外查询 . -- 子查询 -- 查询的条件来自于另一查询的结果 SELECT * FROM t_user WHERE number=(SELECT number FROM t_user WHERE NAME='张三') 当然子查询也有类型,分为以下几种 : 标量子查询(结果集只有一行一列) 列子查询(结果集只有一列多行) 行子查询(结果集有一行多列)(较少) 表子查询(结果集一般为多行多列) 这里我们以新建

  • MySql数据库中的子查询与高级应用浅析

    MySql数据库中的子查询: 子查询:在一条select查询语句中嵌套另一条select语句,其主要作用是充当查询条件或确定数据源. 代码案例如下: 例1. 查询大于平均年龄的学生: select * from students where age > (select avg(age) from students); 例2. 查询学生在班的所有班级名字: select name from classes where id in (select cls_id from students where

  • 浅谈为什么MySQL不推荐使用子查询和join

    做分页查询: 1.对于mysql,不推荐使用子查询和join是因为本身join的效率就是硬伤,一旦数据量很大效率就很难保证,强烈推荐分别根据索引单表取数据,然后在程序里面做join,merge数据. 2.子查询就更别用了,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,这里多了一个创建和销毁临时表的过程. 3.如果是JOIN的话,它是走嵌套查询的.小表驱动大表,且通过索引字段进行关联.如果表记录比较少的话,还是OK的.大的话业务逻

  • Mysql优化技巧之Limit查询的优化分析

    前言 在实际业务中对于分页来说是一个比较常见的业务需求.那么就会使用到limit查询,当我们在使用Limit查询的时候,在数据比较小.或者只查询前面一部分数据的时候效率是很高的.但是当数据量大的时候,或者查询offset数量比较大的时候,如:limit 100000,20效率往往就不尽人意了.通常的一个办法就是Limit配合order by,如果order by有对用户的索引的话,效率通常是比较不错的. 对于这种情况,最简单的查询就是 使用覆盖索引,查询某些需要的列.这样的效果是很好的 如下面这

  • Mysql中的嵌套子查询问题

    目录 Mysql嵌套子查询 在WHERE子句中使用子查询 单行单列子查询 单行多列子查询. 多行单列子查询 FROM子查询: 总结: select子查询 用子查询 用子查询 Mysql嵌套子查询 子查询就是指的在一个完整的查询语句之中,嵌套若干个不同功能的小查询,从而一起完成复杂查询的一种编写形式,为了让读者更加清楚子查询的概念. 子查询返回结果子查询可以返回的数据类型一共分为四种: 单行单列:返回的是一个具体列的内容,可以理解为一个单值数据: 单行多列:返回一行数据中多个列的内容: 多行单列:

  • mysql千万级数据分页查询性能优化

    mysql数据量大时使用limit分页,随着页码的增大,查询效率越低下. 实验 1.直接使用用limit start, count分页语句: select * from order limit start, count 当起始页较小时,查询没有性能问题,我们分别看下从10, 100, 1000, 10000开始分页的执行时间(每页取20条), 如下: select * from order limit 10, 20 0.016秒 select * from order limit 100, 20

  • MySQL的子查询及相关优化学习教程

    一.子查询 1.where型子查询 (把内层查询结果当作外层查询的比较条件) #不用order by 来查询最新的商品 select goods_id,goods_name from goods where goods_id = (select max(goods_id) from goods); #取出每个栏目下最新的产品(goods_id唯一) select cat_id,goods_id,goods_name from goods where goods_id in(select max(

  • 对MySQL子查询的简单改写优化

    使用过oracle或者其他关系数据库的DBA或者开发人员都有这样的经验,在子查询上都认为数据库已经做过优化,能够很好的选择驱动表执行,然后在把该经验移植到mysql数据库上,但是不幸的是,mysql在子查询的处理上有可能会让你大失所望,在我们的生产系统上就由于碰到了这个问题: select i_id, sum(i_sell) as i_sell from table_data where i_id in (select i_id from table_data where Gmt_create

  • mysql关联子查询的一种优化方法分析

    本文实例讲述了mysql关联子查询的一种优化方法.分享给大家供大家参考,具体如下: 很多时候,在mysql上实现的子查询的性能较差,这听起来实在有点难过.特别有时候,用到IN()子查询语句时,对于上了某种数量级的表来说,耗时多的难以估计.本人mysql知识所涉不深,只能慢慢摸透个中玄机了. 假设有这样的一个exists查询语句: select * from table1 where exists (select * from table2 where id>=30000 and table1.u

随机推荐