Utan förklaringsplanen eller tabelldefinitionen är det verkligen svårt att säga vad som händer. Min första gissning är att du har LOKALA partitionerade index utan year
kolumn. De hjälper till med COUNT(*) på en partition, men de verkar inte användas när du frågar ett enda år (åtminstone 10.2.0.3).
Här är ett litet exempel som återger ditt fynd (och en lösning):
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
Jämför nu de två förklara planerna:
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)
Som du kan se är indexet inte används när du frågar året direkt. När du lägger till årtalet till LOCAL-indexet kommer det att användas. Jag använde COMPRESS 1-instruktionen för att berätta för Oracle att komprimera den första kolumnen. Det resulterande indexet är nästan lika stort som det ursprungliga indexet (tack vare komprimeringen) så prestandan bör inte påverkas.
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...)