I am trying to optimize the following query:
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;
It is pretty simple but it takes about 60-90 seconds to run. cockpit_test.TICKS table contains more than 100M of rows. It also has an index by MDC_ID and DATE_ID columns.
EXPLAIN PLAN gives the following output
"-------------------------------------------------------------------------------------------------------"
"| 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)"
So I am not completely sure what all that means, but it seems that index is being hit and most time is being consumed by accessing rows by index rowid.
Are there any ways to make this query run faster?
UPD
Here is the table definition:
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)
There are 3 indexes on the table:
- Index on MDC_ID
- Compound index on DATE_ID, MDC_ID, TICKSTIME
- Compound index on DATE_ID, MDC_ID
I would check that this explain plan has accurate estimations of the cardinalities. It’s quite typical for the cardinality to poorly estimated when multiple predicates are supplied, and the execution time seems very high for such a small query and estimated sort size (unless you have grossly underpowered storage infrastructure, which again is pretty typical).
Given the duration of the query I’d make sure that the estimate is accurate by invoking dynamic sampling …
If it turns out that the estimated temp space is smaller than realtiy (and you can check that by querying V$SQL_WORKAREA_ACTIVE) then you might have to tweak the memory settings for the session to switch to automatic memory management and increase the sort area size.