zoukankan      html  css  js  c++  java
  • SQL查询中in、exists、not in、not exists的用法与区别

    1、in和exists

    in是把外表和内表作hash(字典集合)连接,而exists是对外表作循环,每次循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的,如果查询的两个表大小相当,那么用in和exists差别不大;如果两个表中一个较小一个较大,则子查询表大的用exists,子查询表小的用in。

    例如:表A(小表),表B(大表)

    方式一:索引使用

    1)select * from A where id in(select id from B)   -->效率低,用到了A表上id列的索引

    2)select * from A where exists(select id from B where id=A.id) -->效率高,用到了B表上id列的索引

    3)select * from B where id in(select id from A)   -->效率高,用到了B表上id列的索引

    4)select * from B where exists(select id from A where id=B.id) -->效率低,用到了A表上id列的索引

    方式二:遍历使用

    1)in()只执行一次,它查出B表中的所有id字段并缓存起来。然后检查A表的id是否与B表中的id相等,如果相等则将A表的记录加入结果集中,直到遍历完A表的所有记录。

    它的查询过程类似于以下代码的执行过程:

    List resultSet = {};

    Array A=(select * from A);

    Array B=(select id from B);

    for(int i=0;i<A.length;i++) {

    for(int j=0;j<B.length;j++) {

    if(A[i].id==B[j].id) {

    resultSet.add(A[i]);

    break;

    }

    }

    }

    return resultSet;

    可以看出,当B表数据较大时不适合使用in(),因为它会把B表数据全部遍历一次。

    如:A表有10000条记录,B表有1000000条记录,那么最多有可能遍历10000*1000000次,效率很差。

    如:A表有10000条记录,B表有100条记录,那么最多有可能遍历10000*100次,遍历次数大大减少,效率大大提升。

    结论:in()适合B表比A表数据小的情况

    2)exists()会执行A.length次,它并不缓存exists()结果集,因为exists()结果集的内容并不重要,重要的是其内查询语句的结果集空或者非空,空则返回false,非空则返回true。

    它的查询过程类似于以下代码的执行过程:

    List resultSet={};

    Array A=(select * from A);

    for(int i=0;i<A.length;i++) {

    if(exists(A[i].id) {  //执行select id from B where B.id=A.id是否有记录返回

    resultSet.add(A[i]);

    }

    }

    return resultSet;

    当B表比A表数据大时适合使用exists(),因为它没有那么多遍历操作,只需要再执行一次查询就行。

    如:A表有10000条记录,B表有1000000条记录,那么exists()会执行10000次去判断A表中的id是否与B表中的id相等。

    如:A表有10000条记录,B表有100000000条记录,那么exists()还是执行10000次,因为它只执行A.length次,可见B表数据越多,越适合exists()发挥效果。

    再如:A表有10000条记录,B表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询数据库,我们都知道查询数据库所消耗的性能更高,而内存比较很快。

    结论:exists()适合B表比A表数据大的情况。

    当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用。

    2、not in 和not exists

    not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的bug。

    请看下面的例子:

    create table A1 (c1 int,c2 int);

    create table A2 (c1 int,c2 int);

    insert into A1 values(1,2);

    insert into A1 values(1,3);

    insert into A2 values(1,2);

    insert into A2 values(1,null);

    select * from A1 where c2 not in(select c2 from A2);                            -->执行结果:无(null)

    select * from A1 where not exists(select c2 from A2 where A2.c2=A1.c2);    -->执行结果:1  3

    正如所看到的,not in出现了不期望的结果集,存在逻辑错误。使用not in(它会调用子查询),而使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录。如果子查询字段有非空限制,这时可以使用not in。

    如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。

    3、in 和 =

    select name from employee where name in('张三','李四','王五');

    select name from employee where name='张三' or name='李四' or name='王五';

    的结果是相同的。

    4.exists防止插入重复记录

    有时需要插入非重复记录,在Mysql中可以使用ignore关键字来忽略已有记录,但是其只能通过主键忽略,不能根据自定义条件忽略。

    其语法为:insert ignore into tableName (column1,column2,……) values (value1,value2,……);

    但是其他数据库不一定提供类似ignore关键字,所以可以使用exists条件句防止插入重复记录。

    insert into A (name,age) select name,age from B where not exists (select 1 from A where A.id=B.id);

    5.关于exists更多说明

    exists用于检查子查询返回的结果集是否为空,该子查询实际上并不返回任何数据,而是返回值true或false。
    语法: exists subQuery

    参数: subQuery 是一个受限的 select 语句 (不允许有 compute 子句和 into 关键字)。

    结果类型: boolean 如果子查询包含行,则返回 true ,否则返回 false 。
    结论:select * from A where exists (select 1 from B where A.id=B.id);

    一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果集非空,则exists子句返回true,这一行方可作为外查询的结果行,否则不能作为结果。

                    --------以上sql内容根据网上提供的资料整理出的结果,均适用与Mysql、Sql Server、Oracle。

  • 相关阅读:
    Phoenix SQL总结
    awk基本用法
    集群性能调优-速度篇
    集群基准性能测试
    服务器基础环境搭建
    kafka命令行操作
    九、spring boot--JPA实现分页和枚举转换
    八、spring boot--mybatis框架实现分页和枚举转换
    七、spring boot开发web应用--mybatis-plus框架实现分页和枚举转换
    六、spring boot开发web应用--mybatis-plus为简化而生
  • 原文地址:https://www.cnblogs.com/zwt-blog/p/5395681.html
Copyright © 2011-2022 走看看