关于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的比较相关推荐

  1. mysql exists依赖查询_MySQL EXISTS 和 NOT EXISTS 子查询

    MySQL EXISTS 和 NOT EXISTS 子查询语法如下: 1 SELECT ... FROM table WHERE EXISTS (subquery) 该语法可以理解为:将主查询的数据, ...

  2. [转载]MySQL exists的用法介绍

    原文摘自:http://www.cnblogs.com/glory-jzx/archive/2012/07/19/2599215.html MySQL exists的用法介绍 有一个查询如下: 1 S ...

  3. mysql exists怎么用_Mysql exists用法小结

    简介 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False. EXISTS 指定一个子查询,检测行的存在.语法:EXISTS subquer ...

  4. mysql exists in join_子查询、left join、 exists 替代 not in

    如果要实现一张表有而另外一张表没有的数据时,我们通常会这么写: SELECT id FROM user WHERE id NOT IN (SELECT id FROM student) not in不 ...

  5. Mysql Exists与in_在MySQL里,有个和in一样的东东叫做exists,但是它比in更牛叉,你会么?...

    我们在学习Yii2的时候,一定接触过这样的where输入 $query->where(["exists",xxxx]); User::find()->where([&q ...

  6. MySQL EXISTS 关键字使用

    是什么? 这个问题其实很好理解,简单来说,EXISTS 就是mysql中的一个关键字. 能干啥? Exists关键字的主要作用就是检查SQL语句中的子查询是否至少会返回一行数据.使用EXISTS 关键 ...

  7. php mysql exists语句_mysql子查询 exists,not exists,all和any

    (1)实现让结果集A - 结果集B:--利用not exists,合并则可用union . exists,not exists:用于判断且获取结果集A是否存在地结果集B中! ==========结果集 ...

  8. mysql exists例子_mysql exists用法

    在mysql中,有个关键字exists比较难理解,今天就来搞明白其含义和应用 exists的使用总是跟子查询关联起来,一种是不相关子查询,对于exists来说更常用的是相关子查询 不相关子查询:子查询 ...

  9. MySQL exists的用法介绍

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

  10. MySQL exists后面的子查询使用

    exists后面(相关子查询) 语法: exists(完整的查询语句) 结果: 1或0 SELECT EXISTS(SELECT employee_id FROM employees WHERE sa ...

最新文章

  1. Win8/Win8.1值得做的十多项优化方法
  2. boost::spirit模块演示了 AST 的生成,然后将其转储为人类可读的格式
  3. Git 内部原理图解——对象、分支以及如何从零开始建仓库
  4. 计算机软件技术基础fifo算法,软件技术基础真题
  5. 硬纪元干货|镁客网萨向东:推动硬科技产业落地,助力传统产业升
  6. jquery的语法结构包括哪几部分?_牙釉质的组织学结构具体包括哪几部分
  7. Direcshow相关资料
  8. ELK pipeline
  9. mysql主从同步开启后的iptables的设定问题
  10. Mybatis缓存的使用和注意事项
  11. 网页CSS常用中英文字体收集
  12. L2:Abbott隐式格式有限差分法解一维明渠非恒定流
  13. java使用itext导出pdf,图片、表格、背景图
  14. Adobe Premiere基础-炫酷文字快闪(十四)
  15. 数据处理第一节:选取列的基本到高级方法
  16. i513500h和r5 5600h选哪个 r55600h和i513500h差多少
  17. VS2017配置PCL1.9(win10环境)
  18. Machine Learning 机器学习
  19. 数据分析常用分析方法
  20. IMX6ULL裸机程序--4.时钟树分析

热门文章

  1. Java基础 第一节 第一课
  2. python取地址符_C中指针符*和取址符
  3. 中国传统四大菜系之:鲁菜
  4. iPhone长截图快捷指令(科技兽修改版)
  5. linux环境使用c语言获取系统时间,并拼接成字符串
  6. SAP中常用SM系列事务代码总结
  7. 网页源代码保护(禁止右键、复制、另存为、查看源文件)
  8. [全网首发]坚果Pro3 root教程 Magisk
  9. C++PrimerPlus 第六章 分支语句和逻辑运算符 - 6.1 if语句
  10. linux安装xbox无线手柄,win10系统如何连接xbox360无线手柄