為什麼將 ROWNUM 添加到查詢會提高性能?
我有兩個疑問:
**1)**這個查詢有一個 ROWNUM 列(執行需要 20 秒):
SELECT ROWNUM ,ROAD_ID ,VERTEX_INDEX ,SDE.ST_X(ST_POINT) AS X ,SDE.ST_Y(ST_POINT) AS Y FROM ( SELECT ROWNUM ,a.ROAD_ID ,b.NUMBERS VERTEX_INDEX ,SDE.ST_PointN(a.SHAPE, b.NUMBERS) AS ST_POINT FROM ENG.ROAD a CROSS JOIN ENG.NUMBERS b WHERE b.NUMBERS <= SDE.ST_NUMPOINTS(a.SHAPE) ) --removed to do explain plan: ORDER BY ROAD_ID, VERTEX_INDEX ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5996 | 322K| | 262 (1)| 00:00:01 | | 1 | COUNT | | | | | | | | 2 | VIEW | | 5996 | 322K| | 262 (1)| 00:00:01 | | 3 | COUNT | | | | | | | | 4 | MERGE JOIN | | 5996 | 1545K| | 262 (1)| 00:00:01 | | 5 | INDEX FULL SCAN | R23715_SDE_ROWID_UK | 30 | 90 | | 1 (0)| 00:00:01 | |* 6 | SORT JOIN | | 3997 | 1018K| 2392K| 261 (1)| 00:00:01 | | 7 | TABLE ACCESS FULL| ROAD | 3997 | 1018K| | 34 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- " 6 - access(""B"".""NUMBERS""<=""SDE"".""ST_NUMPOINTS""(""A"".""SHAPE""))" " filter(""B"".""NUMBERS""<=""SDE"".""ST_NUMPOINTS""(""A"".""SHAPE""))"
**2)**此查詢沒有 ROWNUM 列(執行需要 40 秒):
SELECT RDSEC ,VERTEX_INDEX ,SDE.ST_X(ST_POINT) AS X ,SDE.ST_Y(ST_POINT) AS Y FROM ( SELECT a.RDSEC ,b.NUMBERS VERTEX_INDEX ,SDE.ST_PointN(a.SHAPE, b.NUMBERS) AS ST_POINT FROM INFRASTR.STRLN_ROUTE_SIMPLIFY a CROSS JOIN INFRASTR.NUMBERS b WHERE b.NUMBERS <= SDE.ST_NUMPOINTS(a.SHAPE) ) --removed to do explain plan: ORDER BY RDSEC, VERTEX_INDEX ---------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5996 | 1545K| | 262 (1)| 00:00:01 | | 1 | MERGE JOIN | | 5996 | 1545K| | 262 (1)| 00:00:01 | | 2 | INDEX FULL SCAN | R23715_SDE_ROWID_UK | 30 | 90 | | 1 (0)| 00:00:01 | |* 3 | SORT JOIN | | 3997 | 1018K| 2392K| 261 (1)| 00:00:01 | | 4 | TABLE ACCESS FULL| ROAD | 3997 | 1018K| | 34 (0)| 00:00:01 | ---------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- " 3 - access(""B"".""NUMBERS""<=""SDE"".""ST_NUMPOINTS""(""A"".""SHAPE""))" " filter(""B"".""NUMBERS""<=""SDE"".""ST_NUMPOINTS""(""A"".""SHAPE""))"
為什麼在第一個查詢中添加 ROWNUM 會提高性能?我原以為它會減慢速度,如果有的話。
這裡有一些關於查詢的背景資訊。
發布查詢的兩個版本的查詢計劃(以及另一個版本的確切 SQL 只是為了清楚起見)肯定會有所幫助。我想這樣做會證明以下理論。但是,如果沒有它,我可以猜測可能會發生什麼,但我不能確定。
一般來說,數據庫可以自由地以它期望最有效的任何順序評估查詢的元素。這可能意味著它首先完整地執行內聯視圖,然後應用外部投影,其中包括呼叫
SDE.ST_X
andSDE.ST_Y
函式。或者它可能意味著它轉換查詢,以便為每一行呼叫外部函式,並且外部謂詞(如果有)被推送到內聯視圖中。如果您將 a 添加
rownum
到內聯視圖中,則在任何目前版本的 Oracle 中,您都會阻止優化器將邏輯推送到內聯視圖中,因為優化器無法確定它不會影響返回的結果。從理論上講,未來優化器的某些版本可能足夠聰明,可以計算出在內聯視圖中評估SDE.ST_X
andSDE.ST_Y
函式實際上不會改變rownum
生成的,但推動order by
可能會改變結果,因此允許一些轉換和其他轉換被拒絕。但是目前,添加一個rownum
行為基本上會迫使優化器的手“按原樣”離開內聯視圖。最有可能的是,優化器對各種函式呼叫的成本和選擇性的估計是錯誤的。如果
b.NUMBERS <= SDE.ST_NUMPOINTS(a.SHAPE)
函式比優化器預期的要便宜,並且過濾掉的數據比優化器預期的多,它可能會決定在每一行上呼叫SDE.ST_X
andSDE.ST_Y
比先過濾所有數據然後再通過它第二次更有效呼叫函式並進行排序。理想情況下,您應該為優化器提供有關各種功能的更好統計資訊,以便它可以提出更有效的計劃,而無需添加rownum
(特別是因為該技巧可能會在將來的某個時候突然停止工作)但我’我們當然知道添加一個rownum
如果我需要一個快速而骯髒的修復,像這樣一兩次(以及解釋原因的評論)。