Mysql exists 与 in
今天公司同事反馈一个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 分析过程
查看表上的索引
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)此时表上是有对应字段的索引的,如果索引不存在,需要创建索引。
查看执行计划
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)通过执行计划发现两点问题:
- 外查询表数据量大,21162122,也就是访问了21162122次,而子查询通过索引只访问了一次。
- 发现子查询使用了索引,而外查询表上没有使用索引。
从以上两点发现,说明外查询作为了驱动表。
查看子查询中表的数据量
mysql> select count(*) from AI_AD_U_L_TEMP;
+----------+
| count(*) |
+----------+
| 3791 |
+----------+
1 row in set (0.00 sec)子查询中数据量小,应以子查询为驱动表。应该用exists 应换成in。
调整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)从执行计划中可以看到,两张表都在使用索引。而外表的访问次数也明显下降为子查询表中的行数。大量减少了循环访问外表的次数。
执行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的更多相关文章
- 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 ...
- 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 ...
- 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/ ...
- 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 ...
- mysql exists 如何使用
还没时间看,exists用的少 ==>当你只需要判断后面的查询结果是否存 在时使用exists() http://edu.codepub.com/2011/0208/29218.php 今天正 ...
- MySQL exists的用法介绍
有一个查询如下: 1 SELECT c.CustomerId, CompanyName 2 FROM Customers c 3 WHERE EXISTS( 4 SELECT Or ...
- mysql exists 和 in的效率比较
这条语句适用于a表比b表大的情况 select * from ecs_goods a where cat_id in(select cat_id from ecs_category b); 这条语句适 ...
- MySQL - exists与in的用法
[1]exists 对外表用loop逐条查询,每次查询都会查看exists的条件语句. 当 exists里的条件语句能够返回记录行时(无论记录行是多少,只要能返回),条件就为真 , 返回当前loop到 ...
- mysql exists及not exists的使用
对exists及not exists的使用根据下面的示例进行解释 如sql: select sname from student where exists (select * from score)) ...
随机推荐
- Luogu4491 [HAOI2018]染色 【容斥原理】【NTT】
题目分析: 一开始以为是直接用指数型生成函数,后来发现复杂度不对,想了一下容斥的方法. 对于有$i$种颜色恰好出现$s$次的情况,利用容斥原理得到方案数为 $$\binom{m}{i}\frac{P_ ...
- SpringMvc如何获取请求头请求体的消息
对接第三方服务,说传递的POST请求中,Request Header中有需要的参数,Request Body为XML格式,包括创建消息正文和属性. 刚开始我以为可以通过 HttpServletRequ ...
- wiki leaks file link url
wiki leaks file link url XXX发表于2010-08-07 15:54:56 原始来源:http://www.wikileaks.org/wiki/Category:China ...
- 「洛谷4197」「BZOJ3545」peak【线段树合并】
题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...
- Matlab 中subsystem mask封装子系统
Icon&port %%外型图表封装 %%.曲线型标注: plot(cos(:*pi),sin(:*pi)) %%.文字型标注: disp('PID\n控制器') %%.曲线加文字型标注: p ...
- CodeForces - 314C Sereja and Subsequences (树状数组+dp)
Sereja has a sequence that consists of n positive integers, a1, a2, ..., an. First Sereja took a pie ...
- 分类器的评价指标-ROC&AUC
ROC 曲线:接收者操作特征曲线(receiver operating characteristic curve),是反映敏感性和特异性连续变量的综合指标,roc 曲线上每个点反映着对同一信号刺激的感 ...
- IntelliJ IDEA 2017新工具
IntelliJ IDEA 2017 教程之概述 图文详解如何安装 Intellij IDEA 2017 深入剖析 IntelliJ IDEA 2017 的目录结构 图文详解如何配置 IntelliJ ...
- 关于java环境变量配置出现javac命令无法运行的解决办法
昨天一时兴起给电脑刷了机,想着给电脑装个Win10+Linux的双系统, 结果双系统没装好,所有的东西又得重新弄一遍 今天在配置java的时候又出问题了 java,java-version运行成功了, ...
- LeetCode-11. 盛最多水的容器
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两条线, ...