毫不奇怪,Oracle將這視爲一種特殊情況。你可以從執行計劃中看到。隨着天真的(不正確的/不確定的),有時作物了限制的版本,你會得到SORT ORDER BY
和COUNT STOPKEY
操作:
select *
from my_table
where rownum <= 7
order by price;
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (34)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 13 | 3 (34)| 00:00:01 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | TABLE ACCESS FULL| MY_TABLE | 1 | 13 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=7)
如果只是用一個有序的子查詢,沒有限制,你只能得到SORT ORDER BY
操作:
select *
from (
select *
from my_table
order by price
);
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (34)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 13 | 3 (34)| 00:00:01 |
| 2 | TABLE ACCESS FULL| MY_TABLE | 1 | 13 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
與通常的子查詢/ ROWNUM
構造你得到的東西不同,
select *
from (
select *
from my_table
order by price
)
where rownum <= 7;
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (34)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 1 | 13 | 3 (34)| 00:00:01 |
|* 3 | SORT ORDER BY STOPKEY| | 1 | 13 | 3 (34)| 00:00:01 |
| 4 | TABLE ACCESS FULL | MY_TABLE | 1 | 13 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=7)
3 - filter(ROWNUM<=7)
對於外部查詢,COUNT STOPKEY
操作仍然存在,但內部查詢(內聯視圖或派生表)現在具有SORT ORDER BY STOPKEY
而不是簡單的SORT ORDER BY
。這一切都隱藏在內部,所以我猜測,但它看起來像停止鍵 - 即行號限制 - 被推入子查詢處理,所以實際上子查詢可能只有七行無論如何 - 儘管該計劃的ROWS
價值沒有反映(但是然後你得到相同的計劃與不同的限制),並且它仍然認爲需要單獨應用COUNT STOPKEY
操作。
湯姆凱特覆蓋類的理由in an Oracle Magazine article,談到「頂ñ查詢處理與ROWNUM」時(強調):
有兩種方法可以解決這個:
- 讓客戶機應用程序運行該查詢並獲取前N行。
- 使用查詢作爲內嵌視圖,並使用ROWNUM限制結果,如在SELECT * FROM(your_query_here)WHERE ROWNUM < = N.
第二種方法是通過遠遠優於第一,對於兩個原因。這兩個原因中較小的一個是,客戶端需要較少的工作,因爲數據庫負責限制結果集。更重要的原因是特殊處理數據庫可以做到只給你最上面的N行。使用前N個查詢意味着您已向數據庫提供額外信息。你已經告訴過它,「我只對獲得N行感興趣,我永遠不會考慮其餘的。」現在,直到你考慮分類之前,這聽起來不會太驚人 - 分類如何工作以及服務器需要做什麼。
...然後繼續概述它實際在做什麼,而不是我可以更權威。
有趣的是,我不認爲最終結果集的順序實際上是有保證的;它似乎總是工作,但可以證明你仍然應該在外部查詢上也有一個ORDER BY
以使其完成。看起來這個訂單並不真正存儲在子查詢中,它恰好就是這樣生成的。 (我非常懷疑它會改變,因爲它會破壞太多的東西;這最終看起來類似於表集合表達式,它似乎總是保留它的順序 - 破壞會阻止dbms_xplan
工作,但我確信有其他例子。)
只是作比較,這是什麼ROW_NUMBER()
相當於做:
select *
from (
select ROW_NUMBER() OVER (ORDER BY price) rn, my_table.*
from my_table
) t
where rn <= 7;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 52 | 4 (25)| 00:00:01 |
|* 1 | VIEW | | 2 | 52 | 4 (25)| 00:00:01 |
|* 2 | WINDOW SORT PUSHED RANK| | 2 | 26 | 4 (25)| 00:00:01 |
| 3 | TABLE ACCESS FULL | MY_TABLE | 2 | 26 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN"<=7)
2 - filter(ROW_NUMBER() OVER (ORDER BY "PRICE")<=7)
ROWNUM和ORDER BY都不是關係概念。 –