今天公司同事反馈一个SQL语句删除数据删除了一个小时,还没有删除完,强制中断。 第一眼看到 exists 的时候,脑子里要有这么个概念:

Oracle exists 的效率比in 高。而Mysql 则不一定。 Mysql 使用eixsts 与使用in的规则为:

子查询的表大的时候,使用EXISTS可以有效减少总的循环次数来提升速度;
外查询的表大的时候,使用IN可以有效减少对外查询表循环遍历来提升速度。
从本质上讲,exists 是以外查询为驱动表,而in 是以子查询为驱动表(驱动表决定了以 哪个结果集作为nestloop的对比依据)。

3.1.1 SQL

DELETE t FROM   o.`AI_AD_U_L` t   WHERE EXISTS (SELECT     1   FROM     o.`AI_AD_U_L_TEMP`  AS a   WHERE a.`ca_id`=t.`ca_id`);

3.1.2 分析过程

  1. 查看表上的索引

    mysql> show index from AI_AD_U_L;
    +-----------+------------+---------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +-----------+------------+---------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | AI_AD_U_L | 0 | PRIMARY | 1 | prod_inst_id | A | 21162012 | NULL | NULL | | BTREE | | |
    | AI_AD_U_L | 1 | ai_sync_prod_level_cust_addr_id | 1 | cust_addr_id | A | 8266746 | NULL | NULL | YES | BTREE | | |
    | AI_AD_U_L | 1 | ai_sync_prod_level_mac | 1 | mac | A | 12227460 | NULL | NULL | YES | BTREE | | |
    +-----------+------------+---------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    3 rows in set (0.00 sec)
    mysql> show index from AI_AD_U_L_TEMP;
    +----------------+------------+-------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
    +----------------+------------+-------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    | AI_AD_U_L_TEMP | 1 | idx_cust_addr_id2 | 1 | cust_addr_id | A | 2366 | NULL | NULL | YES | BTREE | | |
    | AI_AD_U_L_TEMP | 1 | idx_prod_inst_id | 1 | prod_inst_id | A | 3791 | NULL | NULL | | BTREE | | |
    +----------------+------------+-------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
    2 rows in set (0.00 sec)

    此时表上是有对应字段的索引的,如果索引不存在,需要创建索引。

  2. 查看执行计划

    mysql> explain DELETE   t FROM   o.`AI_AD_U_L` t WHERE EXISTS   (SELECT     1   FROM     o.`AI_AD_U_L_TEMP` AS a   WHERE a.prod_inst_id = t.prod_inst_id);
    +----+--------------------+-------+------------+------+------------------+------------------+---------+-----------------------+----------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+--------------------+-------+------------+------+------------------+------------------+---------+-----------------------+----------+----------+-------------+
    | 1 | DELETE | t | NULL | ALL | NULL | NULL | NULL | NULL | 21162122 | 100.00 | Using where |
    | 2 | DEPENDENT SUBQUERY | a | NULL | ref | idx_prod_inst_id | idx_prod_inst_id | 8 | o.t.prod_inst_id | 1 | 100.00 | Using index |
    +----+--------------------+-------+------------+------+------------------+------------------+---------+-----------------------+----------+----------+-------------+
    2 rows in set, 1 warning (0.01 sec)

    通过执行计划发现两点问题:

    1. 外查询表数据量大,21162122,也就是访问了21162122次,而子查询通过索引只访问了一次。
    2. 发现子查询使用了索引,而外查询表上没有使用索引。

    从以上两点发现,说明外查询作为了驱动表。

  3. 查看子查询中表的数据量

    mysql> select count(*) from AI_AD_U_L_TEMP;
    +----------+
    | count(*) |
    +----------+
    | 3791 |
    +----------+
    1 row in set (0.00 sec)

    子查询中数据量小,应以子查询为驱动表。应该用exists 应换成in。

  4. 调整SQL语句并查看执行计划 将exists 改为in 的用法 。

    mysql> explain DELETE   t FROM   o.`AI_AD_U_L` t WHERE t.prod_inst_id in  (SELECT prod_inst_id FROM     o.`AI_AD_U_L_TEMP` AS a   );
    +----+-------------+-------+------------+--------+------------------+------------------+---------+-----------------------+------+----------+------------------------+
    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+-------+------------+--------+------------------+------------------+---------+-----------------------+------+----------+------------------------+
    | 1 | SIMPLE | a | NULL | index | idx_prod_inst_id | idx_prod_inst_id | 8 | NULL | 3791 | 100.00 | Using index; LooseScan |
    | 1 | DELETE | t | NULL | eq_ref | PRIMARY | PRIMARY | 8 | o.a.prod_inst_id | 1 | 100.00 | NULL |
    +----+-------------+-------+------------+--------+------------------+------------------+---------+-----------------------+------+----------+------------------------+
    2 rows in set (0.00 sec)

    从执行计划中可以看到,两张表都在使用索引。而外表的访问次数也明显下降为子查询表中的行数。大量减少了循环访问外表的次数。

  5. 执行SQL语句

    mysql> DELETE   t FROM   o.`AI_AD_U_L` t WHERE t.prod_inst_id in  (SELECT prod_inst_id FROM     o.`AI_AD_U_L_TEMP` AS a   );
    Query OK, 3525 rows affected (0.44 sec)

    我们看到效果明显, 原来1小时都无法执行完成的SQL,现在只需要0.44秒。

Mysql exists 与 in的更多相关文章

  1. mysql 有报错  ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists

    sh-4.1# /etc/init.d/mysqld status ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql ...

  2. Centos安装完MariaDB后启动不了 MySQL is not running, but lock file (/var/lock/subsys/mysql) exists

    [root@admin-node subsys]# service mysql startStarting MySQL. ERROR! [root@admin-node subsys]# servic ...

  3. ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists

    通过service mysql status 命令来查看mysql 的启动状态 报错如下: ERROR! MySQL is not running, but lock file (/var/lock/ ...

  4. Linux - mysql 异常: ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists

    问题描述 ERROR! MySQL is not running, but lock file (/var/lock/subsys/mysql) exists 解决方案 删除:/var/lock/su ...

  5. mysql exists 如何使用

    还没时间看,exists用的少  ==>当你只需要判断后面的查询结果是否存 在时使用exists() http://edu.codepub.com/2011/0208/29218.php 今天正 ...

  6. MySQL exists的用法介绍

    有一个查询如下: 1 SELECT c.CustomerId, CompanyName   2 FROM Customers c   3 WHERE EXISTS(   4     SELECT Or ...

  7. mysql exists 和 in的效率比较

    这条语句适用于a表比b表大的情况 select * from ecs_goods a where cat_id in(select cat_id from ecs_category b); 这条语句适 ...

  8. MySQL - exists与in的用法

    [1]exists 对外表用loop逐条查询,每次查询都会查看exists的条件语句. 当 exists里的条件语句能够返回记录行时(无论记录行是多少,只要能返回),条件就为真 , 返回当前loop到 ...

  9. mysql exists及not exists的使用

    对exists及not exists的使用根据下面的示例进行解释 如sql: select sname from student where exists (select * from score)) ...

随机推荐

  1. access数据库转sql server中ID的问题

    USE [Task] GO /****** Object: Table [dbo].[Task] Script Date: 04/16/2018 16:14:56 ******/ SET ANSI_N ...

  2. jQuery截取字符串的几种方式

    在我们写前端JS代码的时候,我们会遇到只需要其中部分字符串的时候,下面我就提供集中截取字符串的方法: 1.取后缀 var fileDir = $("#file").val(); v ...

  3. App测试全(转自鲁德)

    1.App测试流程 1.1流程图 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间. 1.3测试资源 ...

  4. Day055--MySQL--外键的变种,表与表的关系,单表查询,多表查询, 内连接,左右连接,全外连接

    表和表的关系 ---- 外键的变种 * 一对多或多对一 多对多 一对一 参考 https://www.cnblogs.com/majj/p/9169416.html 如何找出两张表之间的关系 分析步骤 ...

  5. hdu 4542 "小明系列故事——未知剩余系" (反素数+DFS剪枝)

    传送门 参考资料: [1]:https://blog.csdn.net/acdreamers/article/details/25049767 题意: 输入两个数 type , k: ①type = ...

  6. LA4255/UVa1423 Guess 拓扑排序 并查集

    评分稍微有一点过分..不过这个题目确确实实很厉害,对思维训练也非常有帮助. 按照套路,我们把矩阵中的子段和化为前缀和相减的形式.题目就变成了给定一些前缀和之间的大小关系,让你构造一组可行的数据.这个东 ...

  7. python全栈开发中级班全程笔记(第二模块)第 二 部分:函数基础(重点)

    python学习笔记第二模块         第二部分    :    函数(重点) 一.函数的作用.定义 以及语法 1.函数的作用 2.函数的语法和定义 函数:来源于数学,但是在编程中,函数这个概念 ...

  8. redis3.2.10单实例安装测试

    redis3.2.10单实例安装测试 主要是实际使用环境中使用,为了方便快速部署,特意记录如下: # root用户 yum -y install make gcc-c++ cmake bison-de ...

  9. Docker配置镜像加速

    1.获取镜像地址 1.1.阿里云 打开网址:https://cr.console.aliyun.com/#/accelerator        注册.登录.设置密码        然后在页面上可以看 ...

  10. python中__str__与__repr__的区别

    __str__和repr __str__和__repr__都是python的内置方法,都用与将对象的属性转化成人类容易识别的信息,他们有什么区别呢 来看一段代码 from math import hy ...