• 数据库——SQL中EXISTS怎么用2(转)


    数据库sql语句的exists总结 sql exists in 学习

     

    先来比较下语法:

    --deals=交易表,areas=地域表,例如香港;我们的目的:查看有交易的地域

    select * from areas where id in (select city_id from deals);

    select * from areas where id in   (select city_id from deals where deals.city_id = areas.id);

    select * from areas where exists (select null     from deals where deals.city_id = areas.id);

    区别:

    EXISTS语法并没有说哪个字段落在了子查寻的结果中,而是说exists后面的语句执行的结果是不是有记录,只要有记录,则主查询语句就成立。它代表‘存在’,用来引领嵌套查询的子查询,它不返回任何数据,只产生逻辑真值‘true’与逻辑假值‘False’。由EXISTS引出的子查询,其目标列表达式通常都用*(用null也可以),因为带有EXISTS的子查询只返回真值或假值,给出列名没有实际意义。

     

     

    性能变化的关键:
    #1 执行的先后顺序
    谁是驱动表,谁先执行查询,谁后执行查询
    #2 执行过程
    exists的优点是:只要存在就返回了,这样的话很有可能不需要扫描整个表。  
    in需要扫描完整个表,并返回结果。
    所以,在字表比较小的情况下,扫描全表和部分表基本没有差别;但在大表情况下,exists就会有优势。
    看这两个语句:
    --子查询会执行完全关联,并返回所有符合条件的city_id

    select * from areas where id in   (select city_id from deals where deals.city_id = areas.id);

    --子查询的关联其实是一样的,但子查询只要查到一个结果,就返回了,所以效率还是比较高些的

     

    select * from areas where exists (select null     from deals where deals.city_id = areas.id);

    #3 字表查询的结果
    exists判断子查询的结果是不是存在,但查到什么结果,什么字段,并不关心;
    in      需要子查询查得的结果给主查询使用

     

     

    in 和 Exists的用法区别
    1.
    EXISTS的执行流程        
    select * from t1 where exists ( select null from t2 where y = x )
    可以理解为:
        for x in ( select * from t1 )
        loop
           if ( exists ( select null from t2 where y = x.x )
           then 
              OUTPUT THE RECORD
           end if
        end loop
    对于inexists的性能区别:
       如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in,反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists
       其实我们区分inexists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了
                            
    另外IN时不对NULL进行处理
    如:
    select 1 from dual where null  in (0,1,2,null)
     
    2.NOT IN与NOT EXISTS:        
    NOT EXISTS的执行流程
    select .....
       from rollup R
    where not exists ( select 'Found' from title T 
                                  where R.source_id = T.Title_ID);
    可以理解为:
    for x in ( select * from rollup ) 
           loop
               if ( not exists ( that query ) ) then
                      OUTPUT
               end if;
            end;

    注意:NOT EXISTS与 NOT IN不能完全互相替换,看具体的需求。如果选择的列可以为空,则不能被替换。

    例如下面语句,看他们的区别:
    select x,y from t;
    x               y
    ------          ------
    1               3
    3         1
    1         2
    1         1
    3         1
    5
    select * from t where   x not in (select y from t t2   )
    no rows
            
    select * from t where   not exists (select null from t t2 
                                                       where t2.y=t.x )
    x        y
    ------   ------
    5        NULL
    所以要具体需求来决定

    对于not in和 not exists的性能区别:
        not in只有当子查询中,select 关键字后的字段有not null约束或者有这种暗示时用not in,另外如果主查询中表大,子查询中的表小但是记录多,则应当使用not in,并使用anti hash join.
       如果主查询表中记录少,子查询表中记录多,并有索引,可以使用not exists,另外not in最好也可以用/*+ HASH_AJ */或者外连接+is null
    NOT IN在基于成本的应用中较好

    比如:
    select .....
    from rollup R
    where not exists ( select 'Found' from title T 
                                where R.source_id = T.Title_ID);

    改成(佳)

    select ......
    from title T, rollup R
    where R.source_id = T.Title_id(+)
         and T.Title_id is null;
                                      
    或者(佳)
    sql> select /*+ HASH_AJ */ ...
             from rollup R
             where ource_id NOT IN ( select ource_id
                                                    from title T 
                                                   where ource_id IS NOT NULL )

     

     

    问题和解决

    问题1:

     

    --users表有1000条记录,id自增,id都大于0

    select * from users where exists (select * from users limit 0); --输出多少条记录?

    select * from users where exists (select * from users where id < 0); --输出多少条记录?

    答案(请选中查看):

    10000条

    0条

     原因:

    exists查询的本质,只要碰到有记录,则返回true;所以limit根本就不会去管,或者说执行不到。

     

    问题2:

    exists可以完全代替in吗?

    不能。

    例如:

    --没有关联字段的情况:枚举常量

    select * from areas where id in (4, 5, 6);

    --没有关联字段的情况:这样exists对子查询,要么全true,要么全false

    select * from areas where id in (select city_id from deals where deals.name = 'xxx'); 

     

     

     

    举个相关exists的sql优化例子:

    9、用exists替代in(发现好多程序员不知道这个怎么用): 
    在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。 
    在这种情况下,使用exists(或not exists)通常将提高查询的效率。 
    举例: 
    (低效) 
    select ... from table1 t1 where t1.id > 10 and pno in (select no from table2 where name like 'www%'); 
    (高效) 
    select ... from table1 t1 where t1.id > 10 and exists (select 1 from table2 t2 where t1.pno = t2.no and name like 'www%'); 
    10、用not exists替代not in: 
    在子查询中,not in子句将执行一个内部的排序和合并。 
    无论在哪种情况下,not in都是最低效的 (因为它对子查询中的表执行了一个全表遍历)。 
    为了避免使用not in,我们可以把它改写成外连接(Outer Joins)或not exists。 
    11、用exists替换distinct: 
    当提交一个包含一对多表信息的查询时,避免在select子句中使用distinct. 一般可以考虑用exists替换 
    举例: 
    (低效) 
    select distinct d.dept_no, d.dept_name from t_dept d, t_emp e where d.dept_no = e.dept_no; 
    (高效) 
    select d.dept_no, d.dept_name from t_dept d where exists (select 1 from t_emp where d.dept_no = e.dept_no); 
    exists使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果. 
    12、用表连接替换exists: 
    通常来说,采用表连接的方式比exists更有效率。 
    举例: 
    (低效) 
    select ename from emp e where exists (select 1 from dept where dept_no = e.dept_no and dept_cat = 'W'); 
    SELECT ENAME 
    (高效) 
    select ename from dept d, emp e where e.dept_no = d.dept_no and dept_cat = 'W';

     

     

    R

    R

    R

    +

    R

    R

    R

  • 相关阅读:
    浅谈动态开点线段树
    详解二叉查找树(BST)
    数组的随机打乱
    浅谈迭代加深搜索
    浅谈传递闭包问题
    详解权值线段树
    算法竞赛中桶的概念与应用
    NKOJ 1353 图形面积
    并查集 & 最小生成树详细讲解
    【线段树基础】NKOJ 1321 数列操作
  • 原文地址:https://www.cnblogs.com/Chenshuai7/p/5135703.html
Copyright © 2020-2023  润新知