开发人员给了一个sql ,结构如下delete from B where ID in (select NID from H where guid='xxx');

内部sql满足条件的结果集只有一条,但是整个删除操作执行了将近1分钟,如果是将结果集放在括号里或者将in改为= ,执行的速度可以实现毫秒级别

但是如果内部查询结果集多于一行,采用第一种方案的话需要更改程序,后来又试了一种更改为join,速度也是极快。

测试表,t1.id上有索引,t2.id无索引

mysql> select * from t1;         mysql> select * from t2;    
+------+------+----------+       +------+---------+         
| id   | name | class_id |       | id   | name    |         
+------+------+----------+       +------+---------+         
|    1 | aa   |     NULL |       |    2 | myname2 |         
|    2 | aa   |     NULL |       |    6 | myname5 |         
|    3 | dd   |     NULL |       +------+---------+         
|    6 | cc   |     NULL |       2 rows in set (0.01 sec)   
+------+------+----------+                                  
4 rows in set (0.00 sec)                                    

使用子查询及改为join后的执行计划

mysql> explain delete from t1 where id in (select id from t2 where name='aa');
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | DELETE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
+----+--------------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
2 rows in set (0.00 sec) mysql> explain delete t1.* from t1 inner join t2 where t1.id=t2.id and t2.name='aa';
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where |
| 1 | DELETE | t1 | NULL | ref | idx_id | idx_id | 5 | const | 1 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
2 rows in set (0.01 sec)

对于子查询的执行计划可以看出先对t1进行全表扫描,然后执行select id from t2 where name='aa' and t1.id=t2.id ,如果有值则删除t.* where id=t1.id

而对于改为join的sql来说,优化器会很智能的选取小表来作为驱动表,然后再走索引删除t1.* , 而对于子查询官方文档解释为由外向内执行

为了更加直观的看两种方式的执行过程,打开回话级别的profiling

mysql> show profiles;
+----------+------------+------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+------------------------------------------------------------------------------+
| 3 | 0.00137075 | delete from t1 where id in (select id from t2 where name='aa') |
| 4 | 0.00211725 | explain delete t1.* from t1 inner join t2 where t1.id=t2.id and t2.name='aa' |
| 5 | 0.00132050 | delete t1.* from t1 inner join t2 where t1.id=t2.id and t2.name='aa' |
+----------+------------+------------------------------------------------------------------------------+ mysql> show profile for query 3 mysql> show profile for query 5
-> ; -> ;
+----------------------+----------+ +--------------------------------+----------+
| Status | Duration | | Status | Duration |
+----------------------+----------+ +--------------------------------+----------+
| starting | 0.000388 | | starting | 0.000360 |
| checking permissions | 0.000026 | | checking permissions | 0.000013 |
| checking permissions | 0.000008 | | checking permissions | 0.000007 |
| Opening tables | 0.000105 | | checking permissions | 0.000004 |
| init | 0.000152 | | init | 0.000005 |
| System lock | 0.000083 | | Opening tables | 0.000048 |
| updating | 0.000084 | | init | 0.000048 |
| optimizing | 0.000031 | | deleting from main table | 0.000022 |
| statistics | 0.000083 | | System lock | 0.000028 |
| preparing | 0.000052 | | optimizing | 0.000043 |
| executing | 0.000013 | | statistics | 0.000144 |
| Sending data | 0.000114 | | preparing | 0.000144 |
| executing | 0.000009 | | executing | 0.000009 |
| Sending data | 0.000017 | | Sending data | 0.000246 |
| executing | 0.000005 | | deleting from reference tables | 0.000073 |
| Sending data | 0.000019 | | end | 0.000012 |
| executing | 0.000006 | | end | 0.000010 |
| Sending data | 0.000018 | | query end | 0.000016 |
| end | 0.000019 | | closing tables | 0.000015 |
| query end | 0.000020 | | freeing items | 0.000037 |
| closing tables | 0.000021 | | cleaning up | 0.000039 |
| freeing items | 0.000054 | +--------------------------------+----------+
| cleaning up | 0.000046 | 21 rows in set, 1 warning (0.00 sec)
+----------------------+----------+
23 rows in set, 1 warning (0.01 sec)

我第一眼关注的是两条语句senting data的次数,子查询对应的sending data是4次,子查询先对外部表进行全表扫描,结果集是4行,然后进行循环遍历拿出每一行与内部查询进行关联,共执行了4次内部查询,并且每次都对内部查询的结果集做一下判断是否有值,如果有值则再进行删除

小小的记录一下,在优化器的探索之路上慢慢爬

MySQL 子查询优化案例的更多相关文章

  1. mysql 子查询优化

    今天用到要查询七天内都没有装机的门店信息,首先想到了用not in,先把装机的userid查出来,然后再id not in,但是这样就必须使用子查询,数据量少还可以,数据量大了的话,肯定效率特别低,因 ...

  2. MySQL子查询优化实例

    优化:子查询改写成关联查询 线上遇到问题,查询较慢,如为对应SQL的查询执行计划: localhost.\G . row *************************** id: select_ ...

  3. mysql子查询案例

    源SQL如下: 创建数据表 CREATE TABLE IF NOT EXISTS tdb_goods(     goods_id SMALLINT UNSIGNED PRIMARY KEY AUTO_ ...

  4. mysql子查询优化

    ,,,) ) LIMIT 第一种方式in where:2000ms SELECT COUNT(*) AS tp_count FROM xxx_b2c_orders o ,,,) and from xx ...

  5. 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)

    原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...

  6. MySQL查询原理及其慢查询优化案例分享(转)

    MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能出色,但所谓“好马配好鞍”,如何能够更 好的使用它,已经成为开发工程师的必修课,我们经常会从职 ...

  7. MySQL实验 子查询优化双参数limit

    MySQL实验 子查询优化双参数limit 没想到双参数limit还有优化的余地,为了亲眼见到,今天来亲自实验一下.   实验准备 使用MySQL官方的大数据库employees进行实验,导入该示例库 ...

  8. Mysql单表访问方法,索引合并,多表连接原理,基于规则的优化,子查询优化

    参考书籍<mysql是怎样运行的> 非常推荐这本书,通俗易懂,但是没有讲mysql主从等内容 书中还讲解了本文没有提到的子查询优化内容, 本文只总结了常见的子查询是如何优化的 系列文章目录 ...

  9. [慢查优化]慎用MySQL子查询,尤其是看到DEPENDENT SUBQUERY标记时

    案例梳理时间:2013-9-25 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助, ...

随机推荐

  1. .aspx设置跨域

    在web.config添加节点 <system.webServer>下添加 <httpProtocol>      <customHeaders>        & ...

  2. 修改输入框placeholder的默认样式

    一般网页中都用到input的placeholder属性,想让这个默认样式和网页保持一致,就需要重新设定样式,百度百度: :-moz-placeholder { / color: #000; opaci ...

  3. ExpandableListView 安卓二级菜单

    ExpandableListView可以显示一个视图垂直滚动显示两级列表中的条目,这不同于列表视图(ListView).ExpandableListView允许有两个层次:一级列表中有二级列表.比如在 ...

  4. IOS之UI异步刷新

    NSOperationQueue     *operationQueue; // for rendering pages on second thread [operationQueue waitUn ...

  5. [总结].net操作MongoDb通用基础类1:

    public class MongoDBHelper { //定义Mongo服务 private MongoServer mongo = null; //获取databaseName对应的数据库,不存 ...

  6. 【数据库-MySQL on Azure】如何使用 MySQL EntityFramework 组件处理 MYSQL PaaS DB

    MySQL Database on Azure 是 Azure 平台上推出的 MySQL 云数据库服务,通过全面兼容 MySQL 协议,为用户提供了一个全托管的性能稳定.可快速部署.高可用.高安全性的 ...

  7. ActiveMQ消息丢失怎么解决?

    在消息发送过程中消息丢失的话该怎么解决(包括网络原因): 解决思路: 可以把消息唯一ID,存到表里面,当消息接受端可以获取到这个ID,就给服务端一个回复IF,消息发送出去,没有回复,THEN一直循环发 ...

  8. 强化学习_Deep Q Learning(DQN)_代码解析

    Deep Q Learning 使用gym的CartPole作为环境,使用QDN解决离散动作空间的问题. 一.导入需要的包和定义超参数 import tensorflow as tf import n ...

  9. poj1142Smith Numbers质因子分解

    题意:一个数不是质数,其质因子的每位加起来等于该数的每位加起来. /* 题意:一个数的所有质因子的每位相加起来等于该数的每位相加起来且该数不能是质数,那么就是史密斯数 tip:对于分解质因子,只需要判 ...

  10. vscode 插件整理

    己亥年  庚午月 癸巳日  宜入宅 忌婚嫁 1.Chinese (Simplified) Language Pack for Visual Studio Code 此中文(简体)语言包为 VS Cod ...