2011-06-16 73 views
4

我不能因爲各種原因整個SQL粘貼,所以考慮這個例子:爲什麼只有當我用where子句查詢子查詢時,這個Oracle 10g SQL纔會運行緩慢?

select * 
from 
    (select nvl(get_quantity(1), 10) available_qty 
    from dual) 
where available_qty > 30; 

get_quantity是一個函數,使得基於多數民衆贊成通過它記錄的ID的計算。如果返回null,我用nvl()用它強制10.

查詢時我使用WHERE子句中的父查詢的運行速度很慢。但是,當我註釋WHERE條款時,它運行速度非常快。我沒有得到的是爲什麼它可以非常快速地顯示數據,但它不能以同樣的速度查詢它。我也在查詢子查詢的結果。我的印象是子查詢返回一個「呈現」數據集。這幾乎就像查詢available_qty標識符導致它引用子查詢中的某些內容一樣。

這就是爲什麼我不認爲get_quantity功能的內容是與此有關,所以我沒有打擾張貼。相反,我認爲這是我對Oracle如何處理子查詢和什麼的誤解。

你們任何一位Oracle專家都知道我做錯了什麼嗎?

事後反思:當我輸入這個問題的標籤時,標籤「相關的子查詢」出現了。在做一些快速研究時,似乎這種類型的子查詢在某種程度上取決於外部查詢。這可能與我的問題有關嗎?

+0

你有沒有忽略一些內部查詢 - ?有沒有FROM子句 – antlersoft 2011-06-16 19:12:54

+0

我只是用雙表固定它。該查詢實際上不起作用。我只是用一個準系統的例子來展示一個概念。 – oscilatingcretin 2011-06-16 19:14:59

+0

我仍然認爲你已經留下了太多的問題以便得到一個很好的答案 - 儘管如此,我懷疑你在事後纔會走上正確的軌道。where子句可能會在子查詢中添加一個條件,使得它對主查詢的每一行都進行重新評估,而不是隻評估一次。 – antlersoft 2011-06-16 19:23:14

回答

7

讓我們來嘗試一個實驗。首先,我們將運行以下查詢:

select lvl, rnd 
from (select level as lvl from dual connect by level <= 5) a, 
    (select dbms_random.value() rnd from dual) b; 

「一」子查詢將返回值5行從1到5的「B」子查詢將返回一行與一個隨機值。如果函數在兩個表連接之前(通過笛卡兒)運行,則每行將返回相同的隨機值。實際結果:

 LVL  RND 
---------- ---------- 
     1 .417932089 
     2 .963531718 
     3 .617016889 
     4 .128395638 
     5 .069405568 

5 rows selected. 

顯然函數爲每個參加行的運行,而不是在連接前的子查詢。這是Oracle優化程序決定查詢的最佳路徑是按照該順序執行操作的結果。爲了防止這種情況發生,我們必須在第二個子查詢中添加一些東西,使Oracle在執行聯接之前完整地運行子查詢。我們將rownum添加到子查詢中,因爲Oracle知道如果在加入之後運行,rownum將會更改。下面的查詢說明了這一點:

select lvl, rnd from (
select level as lvl from dual connect by level <= 5) a, 
(select dbms_random.value() rnd, rownum from dual) b; 

你可以從結果看,該功能只在這種情況下運行一次:

 LVL  RND 
---------- ---------- 
     1 .028513902 
     2 .028513902 
     3 .028513902 
     4 .028513902 
     5 .028513902 

5 rows selected. 

在你的情況,這很可能是過濾器提供where子句正在使優化器採取不同的路徑,重複運行該函數,而不是一次。通過讓Oracle按照書面運行子查詢,您應該獲得更一致的運行時間。

+0

BRILLIANT。我只是將rownum添加到子查詢的select語句中,整個運行時間從6.069秒變爲0.171秒。你應該得到瘋狂的互聯網點! – oscilatingcretin 2011-06-16 20:02:54