2013-01-05 9 views
6

Oracle 11gを使用しています。メイン表には約10mのレコードがあります。ここに私のクエリは次のとおりです。COUNT()でのOracleパフォーマンスの問題

SELECT COUNT (*) 
    FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS 
WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1; 

コストは3736ですが、私はこのフォームにそれを変更する場合:

SELECT COUNT (*) FROM 
    (SELECT 1 FROM CONTACT c INNER JOIN STATUS S ON C.STATUS = S.STATUS 
    WHERE C.USER = 1 AND S.REQUIRE = 1 AND ROWNUM = 1); 

コストは5になりました!これら2つのクエリの違いは何ですか?ここで

は、両方のクエリのための計画を説明している:

最初のクエリ:

---------------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name     | Rows | Bytes | Cost (%CPU)| Time  | 
---------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |       |  1 | 10 | 3736 (1)| 00:00:45 | 
| 1 | SORT AGGREGATE    |       |  1 | 10 |   |   | 
|* 2 | COUNT STOPKEY    |       |  |  |   |   | 
| 3 | NESTED LOOPS    |       | 4627 | 46270 | 3736 (1)| 00:00:45 | 
| 4 |  TABLE ACCESS BY INDEX ROWID| CONTACT     | 6610 | 33050 | 3736 (1)| 00:00:45 | 
|* 5 |  INDEX RANGE SCAN   | IX_CONTACT_USR   | 6610 |  | 20 (0)| 00:00:01 | 
|* 6 |  INDEX RANGE SCAN   | IX_CONTACT_STATUS  |  1 |  5 |  0 (0)| 00:00:01 | 
---------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    2 - filter(ROWNUM=1) 
    5 - access("C"."USER"=1) 
    6 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1) 

2番目のクエリ:

----------------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name     | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |       |  1 |  |  5 (0)| 00:00:01 | 
| 1 | SORT AGGREGATE     |       |  1 |  |   |   | 
| 2 | VIEW       |       |  1 |  |  5 (0)| 00:00:01 | 
|* 3 | COUNT STOPKEY    |       |  |  |   |   | 
| 4 |  NESTED LOOPS    |       |  2 | 20 |  5 (0)| 00:00:01 | 
| 5 |  TABLE ACCESS BY INDEX ROWID| CONTACT     |  3 | 15 |  5 (0)| 00:00:01 | 
|* 6 |  INDEX RANGE SCAN   | IX_CONTACT_USR   | 6610 |  |  3 (0)| 00:00:01 | 
|* 7 |  INDEX RANGE SCAN   | IX_CONTACT_STATUS  |  1 |  5 |  0 (0)| 00:00:01 | 
----------------------------------------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    3 - filter(ROWNUM=1) 
    6 - access("C"."USER"=1) 
    7 - access("C"."STATUS"="S"."STATUS" AND "S"."REQUIRE"=1) 

私は2つのクエリを実行し、最初の1時にはコストの45S + (例えば、最初に実行するか、ユーザーIDを変更する)、それ以外の場合は、<になります。私はまったく違うのか、おそらくdbキャッシュなのか全く分かりません。

私が2番目のクエリを実行したとき、私はいつも1で結果を得ることができます。だから、私は2番目の方が良いと思うが、それがたくさん改善する理由はない。

+0

提供される説明計画についてのコメント:私が想定したように、あなたの2つのクエリーは異なるものではありません。唯一の違いは2行目で、それはパフォーマンスに影響しません...(また、実行計画では必ずしも実行計画に収まるものではないことに気がつくので、私はそれをトレースするように提案しています) – igr

+0

良い質問と間違いなく別の回答!私はあなたが多くのことをしていない計画を入れてうれしく思います。 – glh

+0

両方のクエリの説明計画を投稿すると、テーブルの統計情報をよりよく理解し、2つのクエリを比較するのに役立ちます。 http://www.oraclebin.com/2012/12/explain-plan-how-to-get-execution-plan.htmlあなたは彼らが実際の異なる量で実行 –

答えて

1

CONTACTテーブルにアクセスする実行計画の行を比較すると、どこに違いがあるのか​​が分かります(最初の行の列を参照)。

まず:

| 4 |  TABLE ACCESS BY INDEX ROWID| CONTACT     | 6610 | 33050 | 3736 (1)| 00:00:45 | 

第二:あなたは6610行を取得しているように、第1の例では

| 5 |  TABLE ACCESS BY INDEX ROWID| CONTACT     |  3 | 15 |  5 (0)| 00:00:01 | 

ROWNUM = 1述語は、CONTACTテーブルがアクセスされた後までは適用されませんこのテーブルから返されます。 2番目のクエリオプティマイザでは3しか返されませんでした。これは何桁も少ないので、2番目のクエリがより速く完了していることがわかります。

「遅い」クエリの2回目の実行が「高速」である理由については、データがディスクからバッファキャッシュにロードされているため、アクセスがはるかに迅速です。

+0

これは、オプティマイザの見積もりがどのように変化するかを示しているに過ぎません。述語情報セクションは両方の場合に両方のテーブルの後に 'filter(ROWNUM = 1)'が適用されることを意味します。 –

+0

あなたはそうです、両方のケースでフィルタを適用しており、説明計画は単なる見積もりに過ぎません。一定であるために、我々は、SQLトレースからの出力を確認する必要があると思いますが、ポスターの実証試験では計画のショーは何を確認するために表示されます。最初のクエリが第二であることを 'CONTACT'テーブルから複数の行にアクセスしていること。 –

+2

私はいくつかのテストを実行したと説明計画が質問に示しているものと一致しますが、TKPROFの結果は、それが常に両方のクエリでは、両方のテーブルから1行のみにアクセスするということを示しています。だから、効果が完全にダウンし、キャッシュにあるとクエリの間には差が –

1

おそらくそれは単なる見積もりの​​違いであり、同じ実行統計を持つ可能性があります。実際のデータを取得するには+ tkprofの両方をトレースします。 さらに、オプティマイザロジックの背後に詳細が必要な場合は、イベント10053でハード解析を実行してください。

1

コストはクエリの要因ではなく、サーバーによっても異なります。またはI/Oコストでは、列カーディナリティ、クエリの条件のために、多少のコストがかかります。もしあなたがクエリーに関する多くの明確化を見たいのであれば、説明プランやTKPROOFを手に入れてください。そうすれば、フル・テーブル・スキャンが行われるか、どのインデックスが実行されて実行時間になるかを知ることができます。

関連する問題