2012-02-10 6 views
1

によって誘発されたthis question私はrank()関数をテストし、サブクエリがランクよりも効率的でないかどうかを調べることにしました。パフォーマンス:rank()とサブクエリ。サブクエリのコストが安い?

create table teste_rank (codigo number(7), data_mov date, valor number(14,2)); 
alter table teste_rank add constraint tst_rnk_pk primary key (codigo, data_mov); 

と一部のレコードを挿入...

declare 
    vdata date; 
begin 
    dbms_random.initialize(120401); 
    vdata := to_date('04011997','DDMMYYYY'); 
    for reg in 1 .. 465 loop 
    vdata := to_date('04011997','DDMMYYYY'); 
    while vdata <= trunc(sysdate) loop 
     insert into teste_rank 
      (codigo, data_mov, valor) 
     values 
      (reg, vdata, dbms_random.value(1,150000)); 
     vdata := vdata + 2; 
    end loop; 
    commit; 
    end loop; 
end; 
/

そして2つのquerysテスト:だから私は、テーブルを作成し

select * 
    from teste_rank r 
where r.data_mov = (select max(data_mov) 
         from teste_rank 
         where data_mov <= trunc(sysdate) 
         and codigo = 1) 
    and r.codigo = 1; 

Explain Plan for sub query


select * 
    from (select rank() over (partition by codigo order by data_mov desc) rn, t.* 
      from teste_rank t 
      where codigo = 1 
      and data_mov <= trunc(sysdate)) r 
where r.rn = 1; 
0123を

Explain plan rank()

ご覧のとおり、サブクエリのコストはrank()よりも低くなります。これは正しいですか?そこに何か不足していますか?

PS:テーブルの完全なクエリと低コストのサブクエリでもテストされています。

EDIT

は、私は2つのクエリののTKPROF生成された(1をトレースし、シャットダウンデータベース、スタートアップの第二トレースさ)。 rank()

call  count  cpu elapsed  disk  query current  rows 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
Parse  1  0.00  0.02   3   3   0   0 
Execute  1  0.00  0.00   0   0   0   0 
Fetch  2  0.00  0.00   9   19   0   1 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
total  4  0.01  0.03   12   22   0   1 

については、サブクエリ

call  count  cpu elapsed  disk  query current  rows 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
Parse  1  0.00  0.02   3   5   0   0 
Execute  1  0.00  0.00   0   3   0   0 
Fetch  2  0.00  0.00   1   4   0   1 
------- ------ -------- ---------- ---------- ---------- ---------- ---------- 
total  4  0.00  0.02   4   12   0   1 

については

私は、サブクエリがランクよりも常に少ない効率的な意志はないと結論することはできますか?サブクエリの代わりにランクが示されるのはいつですか?

+0

テーブルとインデックスを分析しましたか? –

+0

(これが動作するのかどうかはわかりませんが、いくつかのルールに反していますが..) @Justin Cave、このクエストは他の投稿のあなたの答えと関連していますので、どうぞご覧ください。 –

答えて

2

あなたの質問が本当にわかりません。はい、これらの2つの実行計画によれば、この場合、サブクエリメソッドの期待コストは低くなります。興味のある行をすばやく見つけるために索引を使用できるので、驚くようなことではありません。この場合、サブクエリはPK索引の非常に迅速なスキャンのみを実行する必要があります。副照会が索引の一部ではない列を含む場合は、状況が異なる可能性があります。

rank()を使用するクエリでは、すべての一致する行を取得してランク付けする必要があります。私は、オプティマイザがトップnのクエリであることを認識するための短絡ロジックを持っているとは信じていません。

また、オプティマイザがトップnクエリとして認識するこのフォームを試すこともできます。私はあなたのケースでは、インデックスへの単一の範囲スキャンとそれに続くテーブルアクセスが必要であることを期待しています。

select * 
    from (select * 
      from teste_rank r 
      where data_mov <= trunc(sysdate) 
      and codigo = 1 
     order by data_mov desc) 
    where rownum=1; 
+0

私が言及した質問では、答えの1つは、 'サブクエリ'が 'rank()'より効率が悪いと答えています。私はそれを確認しようとしている。 –

+2

@SérgioMichels:rank()メソッドが常にサブクエリメソッドより効率的であるとは限りません。両方とも、望ましい結果を得るために使用する合理的な手法であり、どちらが効率的であるかは、どの列が関与しているか、それらがどのように索引付けされているか、データサイズおよび分布などの複数の要因に依存する。あなたのケースでは、サブクエリは非常に効率的です。これは、インデックスでカバーされている列を正確に使用でき、追加の並べ替えを避けるためにインデックスエントリの順序を利用できるからです。他の場合には、これは当てはまりません。 –

2

コストは、クエリを実行するために必要なコストベースオプティマイザの見積もりです。

CBOが間違っている可能性があります。統計情報が古くなっている場合は特にそうです。

だから、どうしたらいいですか? 'set autotrace on'で各クエリを実行してみてください。それぞれのクエリでは、いくつのバッファ取得と物理読み込みが実行されますか?つまり、実際にの仕事はどれくらい毎回仕事をしていますか?

希望に役立ちます。

+0

もちろん、物理的な読み取りを見ると、キャッシュが有効になることがあります。 –

+0

@DaveCostaどのようにクエリのキャッシュを避けることができますか? –

+0

@ Mark J. Bobakが答えてくれてありがとう、私はtkprofの結果で私の質問を更新し、質問をよりよく説明しようとしました。あなたは答えに追加する何か新しいことがありますか?もう一度ありがとう:) –

関連する問題