Oracle 查询优化器是否将顶级 where 子句应用于子查询或视图?

Does Oracle Query Optimizer apply top level where clauses to sub queries or views?

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

之后是我的问题:Oracle 查询优化器是否在执行期间将顶级查询的 "where clauses" 应用于子查询(如果适用)?

假设我有一个子查询或视图 returns 一百万行,当 运行 单独使用时,但当与顶级查询结合时,将仅使用其中的 1000 行,由于到顶级查询的 join 子句或 where 子句。 Oracle 是否尝试从子查询中提取所有百万行并在连接期间过滤掉不必要的行,或者 Oracle 查询优化器是否将连接子句或 where 子句从顶级查询移动到子查询以便仅提取行的子集?

请不要给我这样显而易见的答案:"Such a query is a poorly written one and I need to rewrite my query"。有时存在技术或非技术限制,所以我可能无法做到这一点。

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

编辑:以下可用作示例查询。该查询在逻辑上可能不合理,但它确实代表了我的问题的示例。子查询 returns 所有销售额,但顶级查询仅使用今年的销售额。 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'

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;