6

私は Oracle 11g を使用しています。メイン テーブルには約 10m のレコードがあります。これが私のクエリです:

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 つのクエリを実行しました。最初のクエリは 45 秒以上かかる場合があり (最初の実行やユーザー ID の変更など)、それ以外の場合は 1 秒未満です。なぜこんなに違うのか、まったくわかりません。おそらくdbキャッシュですか?

2 番目のクエリを実行すると、常に 1 秒で結果を取得できます。ですから、2 番目の方が優れていると思いますが、大幅に改善される理由はわかりません。

4

3 に答える 3

1

テーブルにアクセスする実行計画の行を比較すると、違いがどこにあるのかがわかりCONTACTます (最初の列の行を見てください)。

初め:

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

2番:

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

最初の例では、テーブルがアクセスROWNUM = 1されるまで述語が適用されないため、このテーブルから行が返されます。2 番目のクエリ オプティマイザでは、 のみが返されました。これは桁違いに少ないため、2 番目のクエリがより速く完了します。CONTACT66103

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

于 2013-01-05T16:09:26.977 に答える
1

ほとんどの場合、それは単なる推定の違いであり、実行統計は同じになります。+ tkprof の両方をトレースして、実際のデータを取得します。また、オプティマイザ ロジックの背後にある詳細が必要な場合は、イベント 10053 でハード パースを実行してください。

于 2013-01-05T06:28:19.177 に答える