2015-10-15 63 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;