暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 相关和非相关子查询之间的区别

askTom 2017-03-20
464

问题描述

嗨,

在许多网站和问题解答社区 (例如Quora等) 中,我读到有关非相关子查询和共同相关子查询之间的区别,基本区别是首先共同相关执行外部查询,然后是子查询
示例

select * from departments dep 
where employee_id in (select employee_id from employees emp where emp.employee_id = dep.employee_id)
复制


但是不相关的查询首先执行内部查询,然后执行外部查询,例如

select * from departments 
where employee_id in (select employee_id from employees);
复制


所以我的问题是
1.Oracle如何具有判断查询是共同关联还是非共同关联的智能?
2.对于所有类型的子查询,它是否遵循相同的select语句执行过程,例如From cluse excution,然后Where子句执行,然后按顺序分组?

专家解答

相关与不相关与Oracle数据库如何处理SQL无关。只是您是否在子查询中包含外部查询中的列。

如果子查询中的一个或多个父表中的列与子查询相关。所以:

select * from departments dep 
where employee_id in (select employee_id from employees emp where emp.employee_id = dep.employee_id)
复制


是相关的,因为dep.employee在嵌套查询中。鉴于:

select * from departments 
where employee_id in (select employee_id from employees);
复制


不相关,因为子查询中没有对部门的引用。

Logically数据库执行外部查询,然后在内部查询中找到匹配的行。但在实践中,优化器可以重写它,以不同的方式处理它们。

通常,优化器会尝试首先访问具有最小结果集的表。例如,下面我创建了两个表。一个有10行,一个有1,000。哪个表是父表,哪个是子查询都没关系。优化器首先选择访问较小的表:

create table t1 as
  select rownum x, 'xxxx' y from dual connect by level <= 1000;

create table t2 as
  select rownum x, 'yyyy' y from dual connect by level <= 10;
 
exec dbms_stats.gather_table_stats(user, 't1');
exec dbms_stats.gather_table_stats(user, 't2');

set serveroutput off
alter session set statistics_level = all;

select * from t1
where  t1.x in (select t2.x from t2);

select * 
from   table(dbms_xplan.display_cursor(null, null, 'BASIC LAST'));

PLAN_TABLE_OUTPUT                                      
EXPLAINED SQL STATEMENT:                               
------------------------                               
select * from t1 where  t1.x in (select t2.x from t2)  
                                                       
Plan hash value: 1167709942                            
                                                       
-------------------------------------                  
| Id  | Operation            | Name |                  
-------------------------------------                  
|   0 | SELECT STATEMENT     |      |                  
|   1 |  HASH JOIN RIGHT SEMI|      |                  
|   2 |   TABLE ACCESS FULL  | T2   |                  
|   3 |   TABLE ACCESS FULL  | T1   |                  
-------------------------------------   

select * from t2
where  t2.x in (select t1.x from t1);

select * 
from   table(dbms_xplan.display_cursor(null, null, 'BASIC LAST'));

PLAN_TABLE_OUTPUT                                      
EXPLAINED SQL STATEMENT:                               
------------------------                               
select * from t2 where  t2.x in (select t1.x from t1)  
                                                       
Plan hash value: 4118005679                            
                                                       
-----------------------------------                    
| Id  | Operation          | Name |                    
-----------------------------------                    
|   0 | SELECT STATEMENT   |      |                    
|   1 |  HASH JOIN SEMI    |      |                    
|   2 |   TABLE ACCESS FULL| T2   |                    
|   3 |   TABLE ACCESS FULL| T1   |                    
-----------------------------------
复制


在这两种情况下,它都将子查询转换为联接。由于这种重写,它可能会以不同于您预期的顺序访问表。整个语句仍将首先处理从句,然后处理where等。但是你不能仅仅通过查看就确定子查询是如何进入这个的。

进一步阅读: 使用子查询:

http://docs.oracle.com/database/122/SQLRF/Using-Subqueries.htm#SQLRF52357

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论