2012-02-03 98 views
7

要在Oracle中查詢top-n行,通常使用ROWNUM。 所以下面的查詢似乎確定(獲取最新的5個金):Oracle ROWNUM性能

select a.paydate, a.amount 
from (
    select t.paydate, t.amount 
    from payments t 
    where t.some_id = id 
    order by t.paydate desc 
) a 
where rownum <= 5; 

但對於非常大的表,它是低效的 - 對我來說,運行約10分鐘。 所以,我想其他的查詢,我結束了這一次它運行了不到一秒鐘:

select * 
from (
    select a.*, rownum 
    from (select t.paydate, t.amount 
     from payments t 
     where t.some_id = id 
     order by t.paydate desc) a 
) 
where rownum <= 5; 

要了解發生了什麼事,我看着每個查詢執行計劃。對於第一個查詢:

SELECT STATEMENT, GOAL = ALL_ROWS 7 5 175 
COUNT STOPKEY   
VIEW 7 5 175 
TABLE ACCESS BY INDEX ROWID 7 316576866 6331537320 
INDEX FULL SCAN DESCENDING 4 6 

而對於第二:

SELECT STATEMENT, GOAL = ALL_ROWS 86 5 175 
COUNT STOPKEY   
VIEW 86 81 2835 
COUNT   
VIEW 86 81 1782 
SORT ORDER BY 86 81 1620 
TABLE ACCESS BY INDEX ROWID 85 81 1620 
INDEX RANGE SCAN 4 81 

顯然,索引全掃描DESCENDING,使低效的大表第一個查詢。但我無法通過查看它們來區分兩個查詢的邏輯。 任何人都可以解釋兩種人類語言查詢之間的邏輯差異嗎?

在此先感謝!

+2

id是綁定變量,否(應該是:id?)如果是這樣,使用了什麼值(相同?) – tbone 2012-02-03 12:30:05

+2

我不認爲你在第二個版本中用於過濾器的'rownum'是保證和第一個一樣;認爲你需要別名你的第二個查詢並引用它,或者在查詢中添加'order by rownum'來反對'a'?我懷疑這會影響速度。 – 2012-02-03 13:12:22

回答

3

首先,如Alex的評論所述,我不確定您的第二個版本是否100%保證給您正確的行 - 因爲查詢的「中間」塊沒有明確的order by ,Oracle沒有義務將行按任何特定順序傳遞給外部查詢塊。但是,似乎並沒有什麼特別的理由可以改變行從最裏面的塊傳遞的順序,所以實際上它可能會起作用。

這就是爲什麼Oracle爲第二個查詢選擇不同的計劃 - 邏輯上不能將STOPKEY操作應用於最內層的查詢塊。

我認爲在第一種情況下,優化器假設id值分佈良好,並且對於任何給定的值,可能會有一些非常近期的事務。由於它可以看到它只需要查找最近5次匹配,因此它計算出使用索引從paydate降序掃描行看起來效率更高,從表中查找相應的id和其他數據,以及當前5場比賽中發現時停止。我懷疑你會發現這個查詢的性能非常不同,具體取決於你使用的具體的id值 - 如果這個id有很多最近的活動,應該很快找到這些行,但是如果它沒有,那麼索引掃描可能需要做更多的工作。

在第二種情況下,我認爲它不能將STOPKEY優化應用到最內層的塊,這是由於嵌套的額外層。在這種情況下,索引全掃描將變得不太吸引人,因爲它總是需要掃描整個索引。因此,它選擇在id(我假設)上進行索引查找,然後在日期上進行實際排序。如果給定的id值與一小部分行相匹配,則這可能會更有效 - 但如果您給出在整個表中散佈很多行的id,則我預計它會變慢,因爲它將具有訪問和排序許多行。

所以,我猜測你的測試已經使用了id這個數值相對較少的行,而這些行並不是最近的。如果這將是一個典型的用例,那麼第二個查詢對你來說可能更好(再一次,我不確定它在技術上保證產生正確的結果集)。但是如果典型值更可能有許多匹配的行和/或更可能有5個最近的行,那麼第一個查詢和計劃可能會更好。

+0

很好的解釋!謝謝。 @Alex:似乎最好在exec計劃中添加「by rownum」命令,因爲它在exec計劃中添加了「SORT ORDER BY STOPRKEY」,而別名「rownum」則刪除了exec計劃中的「COUNT STOPKEY」。但是,正如你所說,我沒有看到速度的變化。 – Bazi 2012-02-04 05:21:57