2

次のようなパーティション分割されたテーブルがあります。

create table demo (
    ID NUMBER(22) not null,
    TS TIMESTAMP not null,
    KEY VARCHAR2(5) not null,
    ...lots more columns...
)

パーティションはTS列にあります (1 年に 1 つのパーティション)。

タイムスタンプを介して多くの検索を行うため、複合インデックスを作成しました。

create index demo.x1 on demo (ts, key);

クエリは次のようになります。

select *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')

私も追加しようとしましand t.KEY = '00101'たが、それは役に立ちません。

しかし、それとEXPLAIN PLAN言う:TABLE ACCESSFULL

#  Operation         Options Object Mode           Cost    Bytes   Cardinality
0  SELECT STATEMENT                ALL_ROWS        583804  287145  2127
1  PARTITION RANGE   ALL                           583804  287145  2127
2  TABLE ACCESS      FULL  HEADER  ANALYZED        583804  287145  2127

インデックスについては言及されていません。何が間違っている可能性がありますか?

[編集] 何らかの理由で、オラクルは操作のコストを完全に誤って計算しました。そのテーブルには 1 億 1,200 万行あります。1 つのパーティションのフル スキャンのコストは、600,000 ではなく、2,000 万である必要があります。そのため、オプティマイザのヒントも無視されます。

[EDIT2] テスト中に、この不可解な結果に出くわしました。これを実行するとselect

select tx_ts
from kt.header
where tx_ts = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')

この EXPLAIN PLAN を取得します。

0  SELECT STATEMENT                             ALL_ROWS  152  15616  1952
1  PARTITION RANGE    ALL                                 152  15616  1952
2  INDEX              FAST FULL SCAN  HEADERX2  ANALYZED  152  15616  1952

そのため、結果として索引付けされた列に自分自身を制限するとselect、Oracle は索引を使用することを決定します。すべての列を取得したい場合は、完全なテーブル スキャンを待つ必要があります。何が起きてる?

[EDIT2] 見つけました。以下の私の答えを見てください。

4

5 に答える 5

5

さて、それは私の側の間違いでした:列はタイプDATEではなく、タイプを持っていましたTIMESTAMP。私が使用したのでto_timestamp()、Oracleはインデックスを使用する方法を見ませんでした。

于 2009-10-20T13:37:15.993 に答える
1

あなたの統計は最新ですか?統計が無効であるということは、索引を使用するよりも全表スキャンの方が高速であるとオラクルが判断している可能性があります。オラクルにフルスキャンを実行するように指示している可能性のあるヒントをクエリで使用していますか?

完全なクエリを提供して、計画の結果を説明してもらえますか?

編集: アーロン、「dbms_stats.gather_schema_stats」または「dbms_stats.gather_table_stats」コマンドを使用して統計を更新できます。コマンドの詳細については、こちらを参照してください。これにより、指定されたスキーマまたはテーブルに関連するすべての統計が更新されます。Oracle の Cost Based Optimiser は、統計を使用して、選択する実行計画を決定します。実際のテーブル サイズは使用されません。テーブルのサイズが大幅に変化した場合 (+/- 10% 程度)、統計を再更新する必要があります。

別物。複合インデックスを使用する場合、オプティマイザーがインデックスを考慮するために、インデックスで使用されるすべての列をクエリで指定する必要があります (また、同じ順序で指定する必要があると思いますが、間違っている可能性があります)。つまり、私がこのものを見たのは久しぶりです)

于 2009-10-15T16:11:28.267 に答える
1

私はパーティショニングの専門家ではありませんが、ここで起こったことは、すべてのパーティションの行をカバーする単一のインデックスであるグローバル インデックスを作成したことだと思います。したがって、オプティマイザーは、相互に排他的な 2 つのアクセス パス ((A) インデックス レンジ スキャン、または (B) パーティション プルーニング) から選択する必要があります。PARTITION RANGE 操作は、B を選択したことを示していると思います。

他の人が示唆しているように、統計を更新すると、動作が変わる可能性があります。インデックスを削除して再作成すると、インデックスに存在していた統計はすべて破棄されます。

タイムスタンプとキーが行を一意に識別する場合は、インデックスを UNIQUE として作成することをお勧めします。また、動作も変わる可能性があります。

ただし、本当の「修正」は、代わ​​りにローカル インデックス (各パーティションに個別のインデックス) を作成することだと思います。これにより、オプティマイザはパーティションのプルーニングとそれに続くインデックス ルックアップを実行できるようになります。正直なところ、これを行うための正確な構文が何であるかはわかりません。個々のパーティション名を明示的に使用して、各パーティションにインデックスを作成するだけかもしれません。

于 2009-10-16T13:54:38.373 に答える
1

他のすべてが失敗した場合は、オプティマイザーのヒントを試すことができます。

select /*+ index(demo.demo demo.x1) */ *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
于 2009-10-16T14:03:37.013 に答える