Oracle

為什麼將 ROWNUM 添加到查詢會提高性能?

  • October 19, 2021

我有兩個疑問:

**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_XandSDE.ST_Y函式。或者它可能意味著它轉換查詢,以便為每一行呼叫外部函式,並且外部謂詞(如果有)被推送到內聯視圖中。

如果您將 a 添加rownum到內聯視圖中,則在任何目前版本的 Oracle 中,您都會阻止優化器將邏輯推送到內聯視圖中,因為優化器無法確定它不會影響返回的結果。從理論上講,未來優化器的某些版本可能足夠聰明,可以計算出在內聯視圖中評估SDE.ST_XandSDE.ST_Y函式實際上不會改變rownum生成的,但推動order by可能會改變結果,因此允許一些轉換和其他轉換被拒絕。但是目前,添加一個rownum行為基本上會迫使優化器的手“按原樣”離開內聯視圖。

最有可能的是,優化器對各種函式呼叫的成本和選擇性的估計是錯誤的。如果b.NUMBERS <= SDE.ST_NUMPOINTS(a.SHAPE)函式比優化器預期的要便宜,並且過濾掉的數據比優化器預期的多,它可能會決定在每一行上呼叫SDE.ST_XandSDE.ST_Y比先過濾所有數據然後再通過它第二次更有效呼叫函式並進行排序。理想情況下,您應該為優化器提供有關各種功能的更好統計資訊,以便它可以提出更有效的計劃,而無需添加rownum(特別是因為該技巧可能會在將來的某個時候突然停止工作)但我’我們當然知道添加一個rownum如果我需要一個快速而骯髒的修復,像這樣一兩次(以及解釋原因的評論)。

引用自:https://dba.stackexchange.com/questions/155953