Raf*_*tro 6 index oracle explain
我对 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');
Run Code Online (Sandbox Code Playgroud)
然后我制定了一些解释计划,结果我无法理解
查询 1:
SELECT * FROM test2 WHERE field3=1;
Run Code Online (Sandbox Code Playgroud)
解释计划:
这里一切正常。使用索引。
查询 2:
SELECT * FROM test2 WHERE upper(field1)='FIELD1=1';
Run Code Online (Sandbox Code Playgroud)
解释计划
一切正常。使用索引。
查询 3:
SELECT /*+ USE_CONCAT */ * FROM test2 WHERE field1='FIELD1=1' OR field3=1;
Run Code Online (Sandbox Code Playgroud)
解释计划
索引用于连接。没问题了。
查询 4:
SELECT /*+ USE_CONCAT */ * FROM test2 WHERE upper(field1)='FIELD1=1' OR field3=1;
Run Code Online (Sandbox Code Playgroud)
解释计划
这里出现了我的问题。为什么不使用 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
);
Run Code Online (Sandbox Code Playgroud)
表明这不是错误统计数据的错,并且还演示了使用的解决方法union all
(但请注意,您需要类似upper(field1)='FIELD1=1 and (field3 is null or field3<>1)
完全等效的查询)
(我的测试是在 10.2 上)