web-dev-qa-db-ja.com

ROWNUMをクエリに追加するとパフォーマンスが向上するのはなぜですか?

2つのクエリがあります。

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を追加するとパフォーマンスが向上するのはなぜですか?もしあれば、それが物事を遅くするだろうと私は思ったでしょう。

クエリに関する背景情報 here があります。

更新:

Explain Planを実行できないと誤って想定していました。クエリを実行するためにGISソフトウェアを使用しています。 SQLplus(またはその他の適切なデータベースソフトウェア)ではありません。

別の方法で教えられた ;現在、DBMS_XPLANを使用してExplain Planを実行しています。

5
Wilson

クエリの2つのバージョンのクエリプラン(およびわかりやすくするために、他のバージョンの正確なSQL)を投稿すると、間違いなく役立ちます。そうすることで、次の理論が証明されると思います。それがなければ、何が起こっているのか推測できますが、確信が持てません。

一般に、データベースは、クエリの要素を最も効率的であると期待される順序で自由に評価できます。つまり、最初にインラインビュー全体を実行し、次に_SDE.ST_X_関数と_SDE.ST_Y_関数の呼び出しを含む外側の投影を適用します。または、すべての行に対して外部関数が呼び出されるようにクエリを変換し、外部述語がある場合はインラインビューにプッシュされることを意味する場合があります。

インラインビューにrownumを追加すると、Oracleの現在のバージョンでは、オプティマイザがロジックにインラインビューにプッシュするのを防ぐことができます。返されます。理論的には、将来のオプティマイザの一部のバージョンは、インラインビューで_SDE.ST_X_および_SDE.ST_Y_関数を評価しても実際に生成されるrownumが変更されないことを理解するのに十分賢いかもしれませんただし、_order by_をプッシュすると結果が変わる可能性があるため、一部の変換は許可され、他の変換は拒否されます。しかし現在のところ、rownumを追加すると、基本的にはオプティマイザの手を強制してインラインビューをそのままにします。

おそらく、オプティマイザによるコストの見積もりと、さまざまな関数呼び出しの選択性がオフになっています。 b.NUMBERS <= SDE.ST_NUMPOINTS(a.SHAPE)関数がオプティマイザが期待するよりも安価であり、オプティマイザが予想するよりもはるかに多くのデータを除外する場合、_SDE.ST_X_および_SDE.ST_Y_を呼び出す方が効率的であると判断する場合があります。最初にすべてのデータをフィルタリングしてから、2番目のパスを使用して関数を呼び出し、並べ替えを行うのではなく、すべての行。理想的には、rownumを追加する必要なしに、より効率的な計画を思い付くことができるように、オプティマイザにさまざまな関数に関するより良い統計を提供します(特にそのトリックが、ある時点で突然動作を停止する可能性があるため)将来)しかし、私が迅速で汚い修正が必要な場合は、このようなrownumを(理由を説明するコメントとともに)1、2回追加することは確かに知られています。

10
Justin Cave