2

次のクエリを最適化しようとしています。

 SELECT   tickstime AS time,
          quantity1 AS turnover
    FROM   cockpit_test.ticks
   WHERE   date_id BETWEEN 20111104 AND 20111109 
     AND   mdc_id IN (297613)
ORDER BY   time;

とてもシンプルですが、実行には約 60 ~ 90 秒かかります。cockpit_test.TICKSテーブルに 100M を超える行が含まれています。また、 MDC_ID列とDATE_ID列による索引もあります。

EXPLAIN PLAN は次の出力を提供します

"-------------------------------------------------------------------------------------------------------"
"| Id  | Operation                    | Name           | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |"
"-------------------------------------------------------------------------------------------------------"
"|   0 | SELECT STATEMENT             |                | 26905 |   604K|       | 11783   (1)| 00:02:22 |"
"|   1 |  SORT ORDER BY               |                | 26905 |   604K|   968K| 11783   (1)| 00:02:22 |"
"|   2 |   TABLE ACCESS BY INDEX ROWID| TICKS          | 26905 |   604K|       | 11596   (1)| 00:02:20 |"
"|*  3 |    INDEX RANGE SCAN          | TICKS_MDC_DATE | 26905 |       |       |    89   (0)| 00:00:02 |"
"-------------------------------------------------------------------------------------------------------"
" "
"Predicate Information (identified by operation id):"
"---------------------------------------------------"
" "
"   3 - access(""MDC_ID""=297613 AND ""DATE_ID"">=20111104 AND ""DATE_ID""<=20111109)"

したがって、それが何を意味するのか完全にはわかりませんが、インデックスがヒットしているようで、ほとんどの時間はインデックス行 ID によって行にアクセスすることによって消費されています。

このクエリをより高速に実行する方法はありますか?

UPD

テーブル定義は次のとおりです。

Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
DATE_ID                                   NOT NULL NUMBER(38)
MDC_ID                                    NOT NULL NUMBER(38)
TICKSTIME                                 NOT NULL DATE
STATE                                     NOT NULL NUMBER(38)
VALUE1                                    NOT NULL FLOAT(126)
VALUE2                                             FLOAT(126)
VOLUME1                                            FLOAT(126)
VOLUME2                                            FLOAT(126)
QUANTITY1                                          NUMBER(38)
QUANTITY2                                          NUMBER(38)

テーブルには 3 つのインデックスがあります。

  • MDC_ID のインデックス
  • DATE_ID、MDC_ID、TICKSTIME の複合インデックス
  • DATE_ID、MDC_ID の複合インデックス
4

2 に答える 2

1

この説明計画がカーディナリティの正確な見積もりを持っていることを確認します。複数の述語が提供されている場合、カーディナリティの推定が不十分になるのは非常に一般的であり、実行時間は、このような小さなクエリと推定されたソート サイズでは非常に長く見えます (ストレージ インフラストラクチャが大幅に不足している場合を除きますが、これもかなり一般的です)。

クエリの期間を考えると、動的サンプリングを呼び出して見積もりが正確であることを確認します...

SELECT
  /*+ dynamic_sampling(4) */
  tickstime AS time,
  quantity1 AS turnover
FROM
  cockpit_test.ticks
WHERE
  date_id BETWEEN 20111104 AND 20111109 and
  mdc_id IN (297613)
ORDER BY
 tickstime;

推定一時領域が実際よりも小さいことが判明した場合 (V$SQL_WORKAREA_ACTIVE を問い合せることで確認できます)、セッションのメモリ設定を微調整して、自動メモリ管理に切り替え、ソート領域のサイズを増やす必要がある場合があります。

于 2012-11-19T09:55:30.593 に答える
1

一般に、Oracle は 2 つの個別のインデックスを組み合わせることはできません (ビットマップ インデックスであり、「通常の」btree インデックスでない場合を除きます)。

mdc_idコラムとは?個別の値が多数ある場合は、 に複合インデックスを作成できますmdc_id, date_id

理論的には、Oracle はインデックスを使用してソートされたデータを返すことができます。この場合、インデックスは on でなければなりませんmdc_id, date_id, time

日付列に日付データ型を使用しないのはなぜですか? この特定のクエリでは、おそらく大きな違いはありませんが、一般に、正しいデータ型を使用すると、Oracle はデータの分布をより適切に判断できます。

于 2012-11-19T09:33:11.340 に答える