説明プランまたはテーブル定義がないと、何が起こっているのかを判断するのは非常に困難です。私の最初の推測では、year
のないローカルパーティションインデックスがあると思います 桁。これらはパーティションのCOUNT(*)に役立ちますが、1年(少なくとも10.2.0.3)をクエリするときには使用されていないようです。
これがあなたの発見(そして回避策)を再現する小さな例です:
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
次に、2つの説明プランを比較します。
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)
ご覧のとおり、インデックスはないです。 年を直接照会するときに使用されます。年をLOCALインデックスに追加すると、その年が使用されます。 COMPRESS 1命令を使用して、最初の列を圧縮するようにOracleに指示しました。結果のインデックスは元のインデックスとほぼ同じサイズであるため(圧縮のおかげで)、パフォーマンスに影響を与えることはありません。
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...)