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)) ... 
随机推荐
- 洛谷P5119 Convent 题解
			题目 很好想的一道二分题,首先,二分一定满足单调性,而题目中非常明显的就是用的车越多,所用时间越少,所以可以枚举时间,判断是否可以比\(m\)少. 然后在二分时,更是要注意下标的一些问题,也要注意车和 ... 
- JSON.stringify的三个参数(转载)
			前段时间勾股有提到stringify是支持三个参数,刷新的了我的认知,后来查到文档才发现还真的是支持三个参数的. 参考资料: stringify stringify方法顾名思义,就是把JSON序列换, ... 
- torch.view()详解及-1参数是什么意思
			经常可以看到调用torch.view(-1,28*28)之类的调用,那么这里的-1是什么意思呢,经过查看文档view()得到了一下结果: view()返回的数据和传入的tensor一样,只是形状不同 ... 
- Linux系统扩容根目录磁盘空间的操作方法
			问题描述 系统的服务无法正常运行,查看磁盘空间,发现根目录已经满了 解决过程 1.添加磁盘空间 2.使用fdisk -l命令查看磁盘信息 3.新建磁盘分区 4.使用fdisk /dev/sda3, 创 ... 
- VUE项目中使用mint-ui框架总结
			针对PC端,element-ui可谓是首选了,UI体验效果很好. element-ui 框架官网:http://element.eleme.io/#/zh-CN/component/installat ... 
- EOF输入
			EOF是一个计算机术语,为End Of File的缩写,在操作系统中表示资料源无更多的资料可读取.资料源通常称为档案或串流.通常在文本的最后存在此字符表示资料结束.是int类型的宏定义,它扩展为负整数 ... 
- MySql数据库字段排序规则不一致产生的一个问题
			最近项目向MySql迁移,迁移完毕后,在获取用户权限时产生了一个异常,跟踪进去获取执行的语句如下, SELECT PermissionId FROM spysxtPermission WHERE (R ... 
- C语言的第一堂课
			感觉茂哥讲了很多,但是有些输入的语句还是没能记住 刚讲的都是概念,看来需要看一下表格,以及C语言的基础 有些意思还不能够理解 略显尴尬 回去把C语言书的各种概念理解一下…… 
- CountDownLatch、CyclicBarrier、Semaphore共同之处与区别以及各自使用场景
			区别 CountDownLatch 使一个线程A或是组线程A等待其它线程执行完毕后,一个线程A或是组线程A才继续执行.CyclicBarrier:一组线程使用await()指定barrier,所有线程 ... 
- socket(TCP)通讯之Python实现
			1.Service address = ('localhost', 9102) # AF_INET = ipv4; SOCK_STREAM:TCP s = socket.socket(socket.A ... 
