Ohne den Erklärungsplan oder die Tabellendefinition ist es wirklich schwer zu sagen, was vor sich geht. Meine erste Vermutung ist, dass Sie LOCAL partitionierte Indizes ohne das year
haben Säule. Sie helfen beim COUNT(*) auf einer Partition, scheinen jedoch nicht verwendet zu werden, wenn Sie ein einzelnes Jahr abfragen (zumindest auf 10.2.0.3).
Hier ist ein kleines Beispiel, das Ihren Befund wiedergibt (und eine Problemumgehung):
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
Vergleichen Sie nun die beiden EXPLAIN-Pläne:
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)
Wie Sie sehen können, ist der Index nicht Wird verwendet, wenn Sie das Jahr direkt abfragen. Wenn Sie das Jahr zum LOCAL-Index hinzufügen, wird es verwendet. Ich habe die Anweisung COMPRESS 1 verwendet, um Oracle anzuweisen, die erste Spalte zu komprimieren. Der resultierende Index hat fast die gleiche Größe wie der ursprüngliche Index (dank der Komprimierung), sodass die Leistung nicht beeinträchtigt werden sollte.
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...)