web-dev-qa-db-ja.com

Oracleのクエリの連結と関数インデックスの使用

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;

計画を説明する:

Explain plan for query 01

ここですべてOK。インデックスが使用されます。

クエリ2

SELECT * FROM test2 WHERE upper(field1)='FIELD1=1';

計画を説明する

Explain plan for query 2

すべてが再び大丈夫です。インデックスが使用されます。

クエリ

SELECT /*+ USE_CONCAT */ * FROM test2 WHERE field1='FIELD1=1' OR field3=1;

計画を説明する

Explain plan for query 3

インデンクスは連結で使用されます。再び問題ありません。

クエリ4

SELECT /*+ USE_CONCAT */ * FROM test2 WHERE upper(field1)='FIELD1=1' OR field3=1;

計画を説明する

Explain plan for query 4

ここで私の問題が発生します。 test2_idx1が使用されないのはなぜですか?関数インデックスだからでしょうか。この場合の回避策はありますか?

よろしくお願いします。

6
Rafa de Castro

これはオプティマイザの制限(またはおそらくバグ)のようです。

このクエリの計画:

_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
);
_

explain

これは悪い統計のせいではないことを示し、_union all_を使用した回避策も示します(ただし、まったく同じクエリにはupper(field1)='FIELD1=1 and (field3 is null or field3<>1)のようなものが必要です)

(私のテストは10.2でした)