2012-02-03 16 views
7

Oracleでは、トップNの行を問い合せるには、ROWNUMを使用するのが一般的です。 だから、次のクエリは、(最新の5回の支払いを取得します)[OK]を思わ: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分間実行します。 は、だから私は他のクエリを試みたが、私は秒未満のために実行されます。この1になってしまった。何が起こっているかを調べるには

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 
明らか

、それは大きなテーブルのための最初のクエリが非効率的になることINDEX FULL SCAN DESCENDINGです。しかし、私は実際にそれらを見て2つのクエリの論理を区別することはできません。 人間の言語での2つのクエリの論理的な違いを誰にも教えてもらえますか?

ありがとうございます!

+2

idはバインド変数です(そうでなければならない:id?)もしあれば、どの値が使用されているか(同じ?) – tbone

+2

2番目のバージョンのフィルターに使用している 'rownum'はそれが最初のものと同じであることが保証されています。 2番目のクエリをエイリアスして参照する必要があると思うか、 'aによって'クエリに対して 'order by rownum'を追加してください。私はこれがスピードに影響を与えているとは思わない。 –

答えて

3

まず、Alexのコメントに記載されているように、2番目のバージョンが100%保証されていることがわかりません。クエリの「中央」ブロックに明示的なオラクル社は、特定の順序で外部問合せブロックに行を渡す義務はありません。しかし、行が最も内側のブロックから渡される順序が変更されるという特別な理由はないように思われるので、実際にはおそらくうまくいくでしょう。

これは、Oracleが2番目の問合せに対して別の計画を選択する理由です。論理的には、最も内側の問合せブロックにSTOPKEY操作を適用できません。

最初のケースでは、オプティマイザはidの値が十分に分散していると仮定しています。また、任意の値に対して、最近のトランザクションがある可能性があります。最も最近の5つの一致を見つける必要があることがわかるので、インデックスを使用して昇順に行をスキャンし、インデックスを使用して行をスキャンし、対応するIDと他のデータをテーブルから検索し、最初の5試合が見つかったら停止します。私はあなたが使用する特定のIDの値に応じてこのクエリの非常に異なるパフォーマンスを見るだろうと思う - IDが最近の活動の多くを持っている場合は、行が非常に迅速に見つかるはずですが、そうでなければ、インデックススキャンもっと多くの仕事をしなければならないかもしれません。

2番目のケースでは、追加のネスティングレイヤーのために最も内側のブロックに最適化を適用できないと私は信じています。その場合、インデックスフルスキャンは、常にインデックス全体をスキャンする必要があるため、魅力的ではありません。したがって、それはid(私は仮定しています)でインデックスルックアップを行い、日付の実際のソートを行います。与えられたidの値が小さな行のサブセットと一致する場合、これはより効率的です - しかし、テーブル全体に多くの行が広がっているidを与えると、それはよりゆっくりになると思います多くの行にアクセスしてソートします。

したがって、あなたのテストでは、最近のものではない行が比較的少ない値のidが使用されていると思います。これが典型的な使用例であれば、2番目のクエリはおそらくあなたにとっては良いでしょう(私は、正しい結果セットを生成することが技術的に保証されているかどうかはわかりません)。しかし、典型的な値が一致する行の数が多く、最近の行が5つ多い可能性が高い場合は、最初の問合せと計画が優れている可能性があります。

+0

すばらしい説明!ありがとう。 @Alex:エスケーププランでは "SORT ORDER BY STOPRKEY"を追加するので、order by rownumを追加する方が良いと思われますが、エイリアスrownumはエグゼクティブプランで "COUNT STOPKEY"を削除します。しかし、あなたが指摘したように、私は速度の変化を見ていません。 – Bazi

関連する問題