【MySQL】exists与in的比较
关于exists代替in
exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当exists里的条件语句能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,返回当前loop到的这条记录,反之如果exists里的条件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,当能返回结果集则为true,不能返回结果集则为false。
假设现在有如下两条SQL语句:
select * from A where exists (select * from B where B.id = A.id);
select * from A where A.id in (select id from B);
查询1可以转化以下伪代码,便于理解:
j = 0;
for (i = 0; i < count(A); i++) {a = get_record(A, i); // 从A表逐条获取记录if (B.id == a.id) // 如果子条件成立result[j++] = a;
}
return result;
大概就是这么个意思,其实可以看到,查询1主要是用到了B表的索引,A表如何对查询的效率影响不大。
假设B表的所有id为1,2,3,查询2可以转换为:
select * from A where A.id = 1 or A.id = 2 or A.id = 3;
这个好理解了,这里主要是用到了A的索引,B表如何对查询影响不大。
如果查询的两个表大小相当,那么用in和exists差别不大。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
实验
准备数据
t_dept表
mysql> create table t_dept like departments;
mysql> insert into t_dept select * from departments;
mysql> alter table t_dept drop index dept_name;mysql> show index from t_dept;
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t_dept | 0 | PRIMARY | 1 | dept_no | A | 9 | NULL | NULL | | BTREE | | |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)mysql> select count(*) from t_dept;
+----------+
| count(*) |
+----------+
| 9 |
+----------+
1 row in set (0.00 sec)
dept_emp表:
mysql> show index from dept_emp;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| dept_emp | 0 | PRIMARY | 1 | emp_no | A | 300188 | NULL | NULL | | BTREE | | |
| dept_emp | 0 | PRIMARY | 2 | dept_no | A | 331570 | NULL | NULL | | BTREE | | |
| dept_emp | 1 | dept_no | 1 | dept_no | A | 8 | NULL | NULL | | BTREE | | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)mysql> select count(*) from dept_emp;
+----------+
| count(*) |
+----------+
| 331603 |
+----------+
1 row in set (0.07 sec)
A为大表,B为小表
使用in查询数据:
mysql> explain select * from dept_emp where dept_no in (select dept_no from t_dept);
+----+-------------+----------+------------+-------+---------------+---------+---------+--------------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+---------------+---------+---------+--------------------------+-------+----------+-------------+
| 1 | SIMPLE | t_dept | NULL | index | PRIMARY | PRIMARY | 4 | NULL | 9 | 100.00 | Using index |
| 1 | SIMPLE | dept_emp | NULL | ref | dept_no | dept_no | 4 | employees.t_dept.dept_no | 41446 | 100.00 | NULL |
+----+-------------+----------+------------+-------+---------------+---------+---------+--------------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.01 sec)
使用in查询数据相当于下面的join:
mysql> explain select de.* from dept_emp de,t_dept d where de.dept_no=d.dept_no;
+----+-------------+-------+------------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
| 1 | SIMPLE | d | NULL | index | PRIMARY | PRIMARY | 4 | NULL | 9 | 100.00 | Using index |
| 1 | SIMPLE | de | NULL | ref | dept_no | dept_no | 4 | employees.d.dept_no | 41446 | 100.00 | NULL |
+----+-------------+-------+------------+-------+---------------+---------+---------+---------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
使用exists查询数据:
mysql> explain select * from dept_emp de where exists (select d.dept_no from t_dept d where d.dept_no=de.dept_no);
+----+--------------------+-------+------------+--------+---------------+---------+---------+----------------------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+--------+---------------+---------+---------+----------------------+--------+----------+-------------+
| 1 | PRIMARY | de | NULL | ALL | NULL | NULL | NULL | NULL | 331570 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | d | NULL | eq_ref | PRIMARY | PRIMARY | 4 | employees.de.dept_no | 1 | 100.00 | Using index |
+----+--------------------+-------+------------+--------+---------------+---------+---------+----------------------+--------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)
dept_emp为大表,t_dept为小表,可见使用in效率更高,扫描的行数更少。
A为小表,B为大表
使用in查询数据:
mysql> explain select * from t_dept d where d.dept_no in (select de.dept_no from dept_emp de);
+----+-------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+----------------------------+
| 1 | SIMPLE | d | NULL | ALL | PRIMARY | NULL | NULL | NULL | 9 | 100.00 | NULL |
| 1 | SIMPLE | de | NULL | ref | dept_no | dept_no | 4 | employees.d.dept_no | 41446 | 100.00 | Using index; FirstMatch(d) |
+----+-------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+----------------------------+
2 rows in set, 1 warning (0.00 sec)
使用exists查询数据:
mysql> explain select * from t_dept d where exists (select de.dept_no from dept_emp de where d.dept_no=de.dept_no);
+----+--------------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+-------------+
| 1 | PRIMARY | d | NULL | ALL | NULL | NULL | NULL | NULL | 9 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | de | NULL | ref | dept_no | dept_no | 4 | employees.d.dept_no | 41446 | 100.00 | Using index |
+----+--------------------+-------+------------+------+---------------+---------+---------+---------------------+-------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec)
t_dept为小表,dept_emp为大表,可见使用in和使用exists效率差不多,扫描的行数一样,为什么?按照之前的分析,子查询表大的用exists效率不应该更高吗?
因为MySQL对in语句做了大量的优化,具体做了啥优化呢?查询的最后显示有一个警告,答案就在这个警告中:
mysql> show warnings;
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select `employees`.`d`.`dept_no` AS `dept_no`,`employees`.`d`.`dept_name` AS `dept_name` from `employees`.`t_dept` `d` semi join (`employees`.`dept_emp` `de`) where (`employees`.`de`.`dept_no` = `employees`.`d`.`dept_no`) |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
【MySQL】exists与in的比较相关推荐
- mysql exists依赖查询_MySQL EXISTS 和 NOT EXISTS 子查询
MySQL EXISTS 和 NOT EXISTS 子查询语法如下: 1 SELECT ... FROM table WHERE EXISTS (subquery) 该语法可以理解为:将主查询的数据, ...
- [转载]MySQL exists的用法介绍
原文摘自:http://www.cnblogs.com/glory-jzx/archive/2012/07/19/2599215.html MySQL exists的用法介绍 有一个查询如下: 1 S ...
- mysql exists怎么用_Mysql exists用法小结
简介 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False. EXISTS 指定一个子查询,检测行的存在.语法:EXISTS subquer ...
- mysql exists in join_子查询、left join、 exists 替代 not in
如果要实现一张表有而另外一张表没有的数据时,我们通常会这么写: SELECT id FROM user WHERE id NOT IN (SELECT id FROM student) not in不 ...
- Mysql Exists与in_在MySQL里,有个和in一样的东东叫做exists,但是它比in更牛叉,你会么?...
我们在学习Yii2的时候,一定接触过这样的where输入 $query->where(["exists",xxxx]); User::find()->where([&q ...
- MySQL EXISTS 关键字使用
是什么? 这个问题其实很好理解,简单来说,EXISTS 就是mysql中的一个关键字. 能干啥? Exists关键字的主要作用就是检查SQL语句中的子查询是否至少会返回一行数据.使用EXISTS 关键 ...
- php mysql exists语句_mysql子查询 exists,not exists,all和any
(1)实现让结果集A - 结果集B:--利用not exists,合并则可用union . exists,not exists:用于判断且获取结果集A是否存在地结果集B中! ==========结果集 ...
- mysql exists例子_mysql exists用法
在mysql中,有个关键字exists比较难理解,今天就来搞明白其含义和应用 exists的使用总是跟子查询关联起来,一种是不相关子查询,对于exists来说更常用的是相关子查询 不相关子查询:子查询 ...
- MySQL exists的用法介绍
有一个查询如下: 1 SELECT c.CustomerId, CompanyName 2 FROM Customers c 3 WHERE EXISTS( 4 ...
- MySQL exists后面的子查询使用
exists后面(相关子查询) 语法: exists(完整的查询语句) 结果: 1或0 SELECT EXISTS(SELECT employee_id FROM employees WHERE sa ...
最新文章
- Win8/Win8.1值得做的十多项优化方法
- boost::spirit模块演示了 AST 的生成,然后将其转储为人类可读的格式
- Git 内部原理图解——对象、分支以及如何从零开始建仓库
- 计算机软件技术基础fifo算法,软件技术基础真题
- 硬纪元干货|镁客网萨向东:推动硬科技产业落地,助力传统产业升
- jquery的语法结构包括哪几部分?_牙釉质的组织学结构具体包括哪几部分
- Direcshow相关资料
- ELK pipeline
- mysql主从同步开启后的iptables的设定问题
- Mybatis缓存的使用和注意事项
- 网页CSS常用中英文字体收集
- L2:Abbott隐式格式有限差分法解一维明渠非恒定流
- java使用itext导出pdf,图片、表格、背景图
- Adobe Premiere基础-炫酷文字快闪(十四)
- 数据处理第一节:选取列的基本到高级方法
- i513500h和r5 5600h选哪个 r55600h和i513500h差多少
- VS2017配置PCL1.9(win10环境)
- Machine Learning 机器学习
- 数据分析常用分析方法
- IMX6ULL裸机程序--4.时钟树分析
热门文章
- Java基础 第一节 第一课
- python取地址符_C中指针符*和取址符
- 中国传统四大菜系之:鲁菜
- iPhone长截图快捷指令(科技兽修改版)
- linux环境使用c语言获取系统时间,并拼接成字符串
- SAP中常用SM系列事务代码总结
- 网页源代码保护(禁止右键、复制、另存为、查看源文件)
- [全网首发]坚果Pro3 root教程 Magisk
- C++PrimerPlus 第六章 分支语句和逻辑运算符 - 6.1 if语句
- linux安装xbox无线手柄,win10系统如何连接xbox360无线手柄