mysql中in和exists区别

inexists

mysql 的多表查询中,始终要遵循的一个原则:小表驱动大表

in

in 关键字进行子查询时,内层查询语句只能 返回一个数据列,这个数据列的值将提供给外层查询语句进行比较操作

SELECT * FROM A WHERE id IN (SELECT id FROM B);

如上述 sql 语句,它的执行流程

  • 先执行 in 中的查询,即 SELECT id FROM B
  • 其次在执行 SELECT * FROM A WHERE A.id = B.id

假设 SELECT id FROM B 查询出有 m 条记录,然后检查 A 表中查询出的 idm 条记录中是否存在,如果存在则将 A 的查询数据加入到结果集中,直到遍历完 A 表中所有的结果集为止

  • B 表数据量很大的时候不适合用 in,因为它有可能最多会将 B 表数据全部扫描一次
  • 如果 A 表有 1000 条记录,B 表有 10000 条记录,那么最多有可能扫描10000 * 1000 次表,效率很差
  • 如果 A 表有1000 条记录,B表有 100 条记录,那么最多有可能扫描 100 * 1000 次,扫描表次数大大减少,效率大大提升

总结:当外层查询表数据量大于子查询表时,则用 in,此时也正是遵循了 小表驱动大表 的原则

exists

概述

exists 关键字后面的参数是一个 任意的子查询sql 对子查询进行运算以判断它是否返回行

  • 如果至少返回一行,那么 exists 的结果为 true,此时外层的查询语句将进行查询
  • 如果子查询没有返回任何行,那么 exists 的结果为 false,此时外层语句将不进行查询
  • 注意:当我们的子查询为 SELECT NULL 时,mysql 仍然认为它是 true

exists 对外表用 loop 逐条查询,每次查询都会查看 exists 的子查询语句,当 exists 里的子查询语句能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,返回当前 loop 到的这条记录;反之,如果 exists 里的条件语句不能返回记录行,则当前 loop 到的这条记录被丢弃

举例

select * from user where exists (select 1);

user 表的记录逐条取出,由于子条件中的 select 1 永远能返回记录行,那么 user 表的所有记录都将被加入结果集,所以与 select * from user 是一样的

select * from A where exists (select * from B where user_id = 0);

可以知道对 A 表进行 loop 时,检查条件语句 select * from B where user_id = 0 由于 user_id 永远不为 0,所以条件语句永远返回空集,条件永远为 false,那么 A 表的所有记录都将被丢弃

总结:如果 A 表有 n 条记录,那么 exists 查询就是将这 n 条记录逐条取出,然后判断 nexists 条件

inexists 用法区别

in 查询的子查询返回结果必须只有一个字段,例如

select * from user where user_id in (select id from B);

不能是

select * from user where user_id in (select id, age from B);

exists 就没有这个限制,可以是任意的子查询

小结

  • in 查询在内部表和外部表上都可以使用到索引
  • exists 查询仅在内部表上可以使用到索引
  • 当子查询结果集很大,而外部表较小的时候,existsBlock 嵌套循环的作用开始显现,并弥补外部表无法用到索引的缺陷,查询效率会优于 in
  • 当子查询结果集较小,而外部表很大的时候,existsBlock 嵌套循环优化效果不明显,in 的外表索引优势占主要作用,此时 in 的查询效率会优于 exists
  • 表的规模不是看内部表和外部表,而是外部表和子查询结果集

猜你喜欢

转载自blog.csdn.net/weixin_38192427/article/details/120519400
今日推荐