Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Pozwól Oracle przekształcić predykaty połączone operatorem OR w operacje UNION ALL

Uważam, że może to mieć coś wspólnego z indeksami istniejącymi w kolumnach, których używasz w OR orzeczenie.

Testowałem używając następujących w 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;
/

Następnie wyjaśniłem następujące zapytania w 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                                

Wygląda więc na to, że podpowiedź nie działa. Następnie dodałem indeks do kolumn x i y:

create index test_x on test (x, y);

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

Ponowne uruchamianie zapytań teraz:

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                                

Wygląda na to, że po dodaniu indeksu (nawet jeśli nie jest używany ) optymalizator zdecydował się mimo wszystko skorzystać z podpowiedzi!

Może mógłbyś tego spróbować?



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak przedstawić dzielenie relacyjne (podstawowe wyrażenie algebry) w kategoriach SQL?

  2. Który jar na serwerze weblogic/innych zasobach może mieć klasę:oracle.security.jps.ee.http.JpsFilter?

  3. Używanie funkcji w klauzuli where z parametrem clob

  4. SQL:jak ograniczyć sprzężenie w pierwszym znalezionym wierszu?

  5. Jak wyłączyć wygaśnięcie hasła Oracle?