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
'sourcecode' 카테고리의 다른 글
jquery 페이드 요소에 '가시성: 숨김' 스타일의 요소가 표시되지 않습니다. (0) | 2023.09.15 |
---|---|
쿼리에서 계산된 열을 기준으로 그룹화하는 방법은 무엇입니까? (0) | 2023.09.15 |
작은 자바스크립트 구현? (0) | 2023.09.15 |
각도 2 : NgModule 메타데이터를 찾을 수 없습니다. (0) | 2023.09.15 |
PowerShell, 웹 요청 및 프록시 (0) | 2023.09.15 |