2015-10-15 36 views
2

Oracle文档说Oracle查询引擎首先执行子查询和视图,然后执行顶级查询。作为一个自然结果,Oracle不允许您在子查询中引用顶级查询的字段值(MSSQL允许这样做)您需要构建一个自足的子查询并将结果连接到顶级查询。Oracle查询优化器是否将子句的子查询或视图的子句应用于子句?

之后,我的问题是:Oracle查询优化器在执行期间是否应用顶级查询的“where子句”进行子查询(适用时)?

比方说,我有一个子查询或视图,在单独运行时返回一百万行,但当与顶级查询连接时,将仅使用这些行中的1000行,这是由于join子句或where子句顶级查询。 Oracle是否尝试从子查询中提取所有数量的行并在连接期间过滤出不必要的行,或者Oracle查询优化器是否将连接子句或从顶级查询中的子句移到子查询中,从而只带来一部分行?

请不要给我明显的答案:“这样的查询是写得不好的,我需要重写我的查询”。有时候在技术或非技术上有限制,所以我可能无法做到这一点。

我知道MSSQL查询优化器为子查询和视图执行此操作,但由于Oracle表示子查询将首先执行,所以我需要询问。 Oracle查询优化器是否这样做?

编辑:以下内容可用作示例查询。该查询可能不是合乎逻辑的声音,但它确实代表我的问题的示例。子查询返回所有销售额,但顶级查询仅使用今年的销售额。 Oracle是否会计算所有销售额或今年的销售额?

select u.user_fullname, s.date, s.total 
from users u 
    inner join (select userID, date, sum(total) as total  
       from sales 
       group by userID, date 
       ) s on s.userID = u.userID 
where s.date > '2015-01-01' 
+1

Oracle的优化可以做和做各种各样的事情,但你的问题似乎更多有关SQL语法感知的限制。但是,如果没有实际的查询,很难回答。 –

+0

您的第一个声明是错误的,当然您可以在Oracle中执行相关子查询。如果知道结果仍然相同,优化器还会尝试将条件推入派生表/子查询或跨连接。但是你的例子实际上写得很差,因为'WHERE'-条件会将连接的结果从Outer更改为Inner。看看优化器的计划,看看实际发生了什么。 – dnoeth

+0

“* Oracle会计算所有销售额还是仅计算今年的销售总额?*”Oracle会实际告诉您 - 只需检查执行计划。 –

回答

1

Oracle经常在不同级别的查询之间移动条件。这被称为谓词推送。逻辑限制可能会阻止子查询和内联视图引用顶级项目,但该限制不适用于Oracle执行的转换查询。

此功能已在Oracle中使用很长时间。文档中有许多关于它的参考,甚至有几个帮助控制它的hints。 (虽然通常你不需要使用提示)。据我所知,没有任何资源可以解释它何时可以工作,但它应该能够在你的例子中工作。有很多情况下谓词推送是可能的,但是没有启用,因为优化器认为它不合理。

这个简单的例子说明谓语动作推:

--Create a simple table. 
drop table test1; 
create table test1(a number primary key, b number); 
insert into test1 select level, 1 from dual connect by level <= 100000; 
commit; 
begin 
    dbms_stats.gather_table_stats(user, 'TEST1'); 
end; 
/

--Create a very slow function. 
create or replace function very_slow(p number) return number authid current_user is 
begin 
    execute immediate 'begin dbms_lock.sleep(1); end;'; 
    return 1; 
end; 
/

--This query only takes 1 second. 
--Without predicate pushing it would take hours. 
select * 
from 
(
    select * 
    from test1 
    where b = very_slow(b) 
) 
where a = 1;