2

Oracle の範囲パーティションを使用して、年の値でパーティション分割された大量のデータがあります。レンジ パーティションを使用しましたが、各パーティションには 1 年間のデータしか含まれていません。特定の年を対象とするクエリを作成すると、オラクルはそのパーティションから情報をフェッチしますが、その年が指定したものであるかどうかを確認します。この年の列はインデックスの一部ではないため、テーブルから年を取得して比較します。クエリがテーブル データをフェッチするたびに、処理が遅くなりすぎることがわかりました。

パーティションには1年分の情報しか含まれていないことが確実にわかっているため、オラクルが年の値を比較するのをどうにかして避けることができますか?

アップデート:

  1. 分割が実行される年のデータ型は、number 型です。

  2. 追加の列は選択していません。a を実行しているだけで、count(*)列が選択されていません。

  3. 条件を削除し、クエリを特定のパーティションにターゲットすると、 select count(*) from table_name partition(part_2004)高速である一方 select count(*) from table where year = 2004で低速になります。

  4. パーティションは数値である年の列にあり、以下のように行われます

    2005 年未満の年 part_2004

    2006 年未満の年 part_2005

    2007 年未満の年 part_2006

...すぐ

4

2 に答える 2

6

説明計画やテーブル定義がなければ、何が起こっているのかを判断するのは非常に困難です。year私の最初の推測は、列のない LOCAL パーティション インデックスがあるということです。それらはパーティションの COUNT(*) に役立ちますが、単一の年を照会する場合 (少なくとも 10.2.0.3) には使用されないようです。

これは、あなたの発見(および回避策)を再現する小さな例です。

SQL> CREATE TABLE DATA (
  2     YEAR NUMBER NOT NULL,
  3     ID NUMBER NOT NULL,
  4     extra CHAR(1000)
  5  ) PARTITION BY RANGE (YEAR) (
  6     PARTITION part1 VALUES LESS THAN (2010),
  7     PARTITION part2 VALUES LESS THAN (2011)
  8  );
Table created

SQL> CREATE INDEX ix_id ON DATA  (ID) LOCAL;
Index created

SQL> INSERT INTO DATA 
  2  (SELECT 2009+MOD(ROWNUM, 2), ROWNUM, 'A' FROM DUAL CONNECT BY LEVEL <=1e4);

10000 rows inserted

SQL> EXEC dbms_stats.gather_table_stats(USER, 'DATA', CASCADE=>TRUE);

PL/SQL procedure successfully completed

次に、2 つの説明プランを比較します。

SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=197 Card=1 Bytes=4)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=197 Card=5000 Bytes=20000)
   3    2       TABLE ACCESS (FULL) OF 'DATA' (TABLE) (Cost=197 Card=5000...)

SQL> SELECT COUNT(*) FROM DATA PARTITION (part1);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=1)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=11 Card=5000)
   3    2       INDEX (FULL SCAN) OF 'IX_ID' (INDEX) (Cost=11 Card=5000)

ご覧のとおり、年を直接クエリする場合、インデックスは使用されません。年を LOCAL インデックスに追加すると、それが使用されます。COMPRESS 1 命令を使用して、最初の列を圧縮するように Oracle に指示しました。結果のインデックスは、(圧縮のおかげで) 元のインデックスとほぼ同じサイズになるため、パフォーマンスに影響はありません。

SQL> DROP INDEX ix_id;
 Index dropped

SQL> CREATE INDEX ix_id ON DATA (year, ID) LOCAL COMPRESS 1;
Index created

SQL> SELECT COUNT(*) FROM DATA WHERE YEAR=2010;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=12 Card=1 Bytes=4)
   1    0   SORT (AGGREGATE)
   2    1     PARTITION RANGE (SINGLE) (Cost=12 Card=5000 Bytes=20000)
   3    2       INDEX (RANGE SCAN) OF 'IX_ID' (INDEX) (Cost=12 Card=5000...)
于 2010-03-29T09:33:06.213 に答える
2

年を確認するためだけにテーブルに行くのは確かですか?他の列が関係している可能性がありますか?

クエリは (パーティション化された) インデックスでのみ機能するはずでしたか?

とにかくテーブルに行く必要がある場合、その余分なチェックはそれほどコストがかかりません (パーティションが正しい場合)。

クエリと実行計画を投稿できますか?

于 2010-03-29T05:25:40.653 に答える