sql >> Base de Datos >  >> RDS >> Oracle

Deje que Oracle transforme los predicados conectados con OR en operaciones UNION ALL

Creo que esto puede tener algo que ver con los índices existentes en las columnas que usa en OR predicado.

Probé usando lo siguiente en 11gR2.

create table scott.test as 
select level l, 
       decode(mod(level,2), 1, 1, 2) x, 
       decode(mod(level,2), 1, 2, 1) y, 
       dbms_random.value(1, 3) z from dual 
connect by level < 1000;
/

begin
   dbms_stats.gather_table_stats('scott', 'test');
end;
/

Luego expliqué las siguientes consultas en TOAD, (EXPLAIN PLAN FOR )

select x, y, z from scott.test
    where (floor(z) = 1 and x = 1) or (floor(z) = 2 and y = 1)
    ;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          4                                
  TABLE ACCESS FULL COS_DM.TEST 10      280     4   

select /*+ USE_CONCAT */ x, y, z from scott.test
where (floor(z) = 1 and x = 1) or (floor(z) = 2 and y = 1)
;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          4                                
  TABLE ACCESS FULL COS_DM.TEST 10      280     4                                


select x, y, z from test where (floor(z) = 1 and x = 1)
union all
select x, y, z from test where (floor(z) = 2 and y = 1)
;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          8                                
  UNION-ALL                                              
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                

Así que parece que la pista no funciona. Luego agregué un índice a las columnas x e y:

create index test_x on test (x, y);

begin
   dbms_stats.gather_table_stats('scott', 'test');
end;
/

Volviendo a ejecutar las consultas ahora:

select x, y, z from scott.test
    where (floor(z) = 1 and x = 1) or (floor(z) = 2 and y = 1)
    ;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          4                                
  TABLE ACCESS FULL COS_DM.TEST 10      280     4   

select /*+ USE_CONCAT */ x, y, z from scott.test
where (floor(z) = 1 and x = 1) or (floor(z) = 2 and y = 1)
;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          8                                
  CONCATENATION                                              
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                

select x, y, z from test where (floor(z) = 1 and x = 1)
union all
select x, y, z from test where (floor(z) = 2 and y = 1)
;

SELECT STATEMENT Optimizer Mode=ALL_ROWS        10          8                                
  UNION-ALL                                              
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                
    TABLE ACCESS FULL   COS_DM.TEST 5   140     4                                

Parece que después de agregar el índice (aunque no se usa ) ¡el optimizador decidió usar la pista después de todo!

¿Quizás podrías probar esto?