sourcecode

Oracle이 OR 연결 술어를 UNION ALL 작업으로 변환할 수 있도록 지원

codebag 2023. 9. 15. 20:59
반응형

Oracle이 OR 연결 술어를 UNION ALL 작업으로 변환할 수 있도록 지원

UNION그리고.UNION ALL다음을 사용하여 쿼리가 동등한 쿼리를 능가할 수 있습니다.OR특정 상황에서 연관된 술어를 사용할 수 있습니다.내가 알기로는, 이것은 부분적으로UNION하위 선택들은 병렬적으로 실행될 수 있고 따라서 그들은 각 부분에 특정한 그들만의 "하위 계획"을 가질 수 있습니다.OR-연결된 술어입니다. 이 술어는 적용 가능한 쿼리 변환이 간단하기 때문에 훨씬 더 최적일 수 있습니다.

하지만 글은OR-연결된 술어는 일반적으로 훨씬 더 읽기 쉽고 간결합니다. 비록 하위 쿼리 인수분해가 a에 적용된다 하더라도.UNION ALL해를 보다제가 궁금한 점은, Oracle 환경에서 비용이 많이 드는 단일 솔루션을 제공할 수 있는 방법이 있는지 여부입니다.OR-연결된 술어를 a로 변환해야 합니다.UNION ALL작전?만약 그러한 힌트/방법이 있다면, 어떤 상황에서 적용될 수 있습니까? (예를 들어, 술어와 관련된 열에 어떤 제약 조건이 존재할 필요가 있습니까?)예:

CREATE TABLE a AS
  SELECT 1 x, 2 y FROM DUAL UNION ALL
  SELECT 2 x, 1 y FROM DUAL;

-- This query...
SELECT * FROM a
WHERE x = 1 OR y = 1

-- Is sometimes outperformed by this one, for more complex table sources...
-- Note: in my case, I can safely apply UNION ALL. I know the two predicates to
-- be mutually exclusive.
SELECT * FROM a
WHERE x = 1
UNION ALL
SELECT * FROM a
WHERE y = 1

참고, 나는 그 힌트를 알고 있습니다.

SELECT /*+ USE_CONCAT */ * FROM a
WHERE x = 1 OR y = 1

하지만 제가 필요로 하는 것을 만들어 내지 못하는 것 같습니다(강제적이지는 않습니다).UNION ALL실행계획의 작업):

-------------------------------------------
| Id  | Operation         | Name | E-Rows |
-------------------------------------------
|   0 | SELECT STATEMENT  |      |        |
|*  1 |  TABLE ACCESS FULL| A    |      2 |
-------------------------------------------

혹시 이 힌트에 제약이 있는 것은 아닐까요?나는 이것을 위해 Oracle 11g2를 사용할 수 있습니다.

이것은 당신이 사용하는 열에 존재하는 인덱스와 관련이 있을 수 있다고 생각합니다.OR술어의

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;
/

그 다음에 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                                

힌트가 안 되는 것 같네요그런 다음 x & y 열에 인덱스를 추가했습니다.

create index test_x on test (x, y);

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

쿼리를 지금 다시 실행하는 중:

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                                

옵티마이저는 (비록 사용되지는 않지만) 인덱스를 추가한 후에 결국 힌트를 사용하기로 결정한 것으로 보입니다!

이거 한 번 해보시겠어요?

옵티마이저가 힌트를 무시하는 경우도 있고, 쿼리를 다른 방식으로 작성해야 하는 경우도 있습니다.UNION ALL을 사용하여 모든 쿼리를 다시 쓰는 대안으로 다음 절만 다시 쓸 수 있습니다.

SELECT * FROM a /* ... you can put here more joins with many tables ... */
WHERE a.rowid in (
    select innerQry.rowid from a innerQry where /*your first clause of OR*/innerQry.x = 1
    union all
    select innerQry.rowid from a innerQry where /*your second clause of OR*/innerQry.y = 1
)

언급URL : https://stackoverflow.com/questions/10494205/let-oracle-transform-or-connected-predicates-into-union-all-operations

반응형