Oracle 11gのインデックスについて理解できない問題があります。
以下を使用してテストデータを作成できます。
create table test2(field1 varchar2(100),field2 varchar2(100),field3 number,field4 varchar2(100));
create index test2_idx1 on test2(upper(field1));
create index test2_idx1b on test2(field1);
create index test2_idx2 on test2(field3);
DECLARE
j NUMBER :=1;
BEGIN
FOR i IN 1..500000
LOOP
INSERT
INTO test2
(field1,field2, field3, field4)
VALUES
('field1='||i,'a', j, 'i' );
IF (i mod 1000)=0 THEN
j := j+1;
END IF;
END LOOP;
COMMIT;
END;
EXEC DBMS_STATS.GATHER_TABLE_STATS ('system', 'test2');
それから私はいくつかの説明計画を立てます
クエリ1:
SELECT * FROM test2 WHERE field3=1;
計画を説明する:
ここですべてOK。インデックスが使用されます。
クエリ2:
SELECT * FROM test2 WHERE upper(field1)='FIELD1=1';
計画を説明する
すべてが再び大丈夫です。インデックスが使用されます。
クエリ:
SELECT /*+ USE_CONCAT */ * FROM test2 WHERE field1='FIELD1=1' OR field3=1;
計画を説明する
インデンクスは連結で使用されます。再び問題ありません。
クエリ4:
SELECT /*+ USE_CONCAT */ * FROM test2 WHERE upper(field1)='FIELD1=1' OR field3=1;
計画を説明する
ここで私の問題が発生します。 test2_idx1が使用されないのはなぜですか?関数インデックスだからでしょうか。この場合の回避策はありますか?
よろしくお願いします。
これはオプティマイザの制限(またはおそらくバグ)のようです。
このクエリの計画:
_SELECT /*+ USE_CONCAT */ * FROM test2 WHERE upper(field1)='FIELD1=1' OR field3=1
union all
(
SELECT * FROM test2 WHERE upper(field1)='FIELD1=1'
union all
SELECT * FROM test2 WHERE field3=1
);
_
これは悪い統計のせいではないことを示し、_union all
_を使用した回避策も示します(ただし、まったく同じクエリにはupper(field1)='FIELD1=1 and (field3 is null or field3<>1)
のようなものが必要です)
(私のテストは10.2でした)