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_IDDATE_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)"

所以我不完全确定这一切意味着什么,但似乎索引正在被命中,并且大部分时间都被索引 rowid 访问行所消耗。

有什么方法可以让这个查询运行得更快吗?

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

一般来说,Oracle 不能组合两个单独的索引(除非它们是位图索引而不是“普通”btree 索引)。

什么是mdc_id柱子?如果它有许多不同的值,您可以在mdc_id, date_id.

理论上,Oracle 可以使用索引来返回排序后的数据。在这种情况下,您的索引应该是 on mdc_id, date_id, time

为什么不为日期列使用日期数据类型?对于这个特定的查询,它可能不会有太大的不同,但总的来说,如果您使用正确的数据类型,Oracle 将能够更好地确定数据的分布。

于 2012-11-19T09:33:11.340 回答
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;

如果事实证明估计的临时空间小于 realtiy(您可以通过查询 V$SQL_WORKAREA_ACTIVE 来检查),那么您可能需要调整会话的内存设置以切换到自动内存管理并增加排序区域的大小。

于 2012-11-19T09:55:30.593 回答