파티션 테이블에 대한 병렬 그룹핑은 세 가지 방식으로 동작할 수 있습니다.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다.
-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 (c1 NUMBER, c2 NUMBER)
PARTITION BY RANGE (c1) (
PARTITION p1 VALUES LESS THAN (2)
, PARTITION p2 VALUES LESS THAN (3)
, PARTITION p3 VALUES LESS THAN (4)
, PARTITION p4 VALUES LESS THAN (5)
, PARTITION p5 VALUES LESS THAN (6)
, PARTITION p6 VALUES LESS THAN (7)
, PARTITION p7 VALUES LESS THAN (8)
, PARTITION p8 VALUES LESS THAN (9)
, PARTITION p9 VALUES LESS THAN (10)
, PARTITION pm VALUES LESS THAN (MAXVALUE)
);
아래 쿼리는 파티션 키인 c1 칼럼을 집계했기 때문에 파티션 그래뉼로 동작합니다. 데이터 분배가 발생하지 않아 성능면에서 효율적이지만 파티션 개수가 병렬도보다 적거나 파티션 크기가 균등하지 않다면 성능 저하가 발생할 수 있습니다. 12.2 버전부터 USE_PARTITION_WISE_GBY 힌트로 동작을 제어할 수 있습니다.
-- 2
SELECT /*+ PARALLEL(2) */
c1, COUNT (*) AS cnt
FROM t1
GROUP BY c1;
--------------------------------------------------------------------------
| Id | Operation | Name | TQ |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | PX PARTITION RANGE ALL| | Q1,00 | PCWC | |
| 4 | HASH GROUP BY | | Q1,00 | PCWP | | -- !
| 5 | TABLE ACCESS FULL | T1 | Q1,00 | PCWP | |
--------------------------------------------------------------------------
Outline Data
-------------
USE_PARTITION_WISE_GBY(@"SEL$1")
아래는 앞선 쿼리에 NO_USE_PARTITION_WISE_GBY 힌트를 사용한 실행 계획입니다. 데이터 분배량을 감소시키기 위해 t1 테이블을 블록 그래률로 읽은 병렬 서버에서 결과를 집계합니다. 집계 결과는 그룹핑할 c1 칼럼의 해시값에 따라 다른 병렬 서버로 분배됩니다. 집계 결과를 분배받은 병렬 서버는 다시 한번 집계를 수행하고 QC로 집계 결과를 전달합니다. 이런 동작을 Group By Push 방식이라고 합니다. 이 방식은 대부분 효율적이지만 첫 번째 집계에서 집계 결과를 감소시키지 못한다면 불필요한 집계에 의해 쿼리의 성능이 저하될 수 있습니다. GBY_PUSHDOWN 힌트로 동작을 제어할 수 있습니다.
-- 3
SELECT /*+ PARALLEL(2) NO_USE_PARTITION_WISE_GBY */
c1, COUNT (*) AS cnt
FROM t1
GROUP BY c1;
------------------------------------------------------------------------------------------
| Id | Operation | Name | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | | |
| 1 | PX COORDINATOR | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | | | Q1,01 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | | | Q1,01 | PCWP | | -- !
| 4 | PX RECEIVE | | | | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | | | Q1,00 | P->P | HASH |
| 6 | HASH GROUP BY | | | | Q1,00 | PCWP | | -- !
| 7 | PX BLOCK ITERATOR | | 1 | 10 | Q1,00 | PCWC | |
| 8 | TABLE ACCESS FULL| T1 | 1 | 10 | Q1,00 | PCWP | |
------------------------------------------------------------------------------------------
Outline Data
-------------
GBY_PUSHDOWN(@"SEL$1")
아래는 앞선 쿼리에 NO_GBY_PUSHDOWN 힌트를 추가한 실행 계획입니다. t1 테이블을 블록 그래률로 읽은 병렬 서버에서 조회 결과를 다른 병렬 서버로 분배합니다. 조회 결과를 분배받은 병렬 서버는 집계를 수행하고 QC로 집계 결과를 전달합니다. 데이터 전송량이 커서 일반적으로 사용되지 않는 방식이지만 그룹핑이 결과를 감소시키지 못하는 경우 그룹핑 횟수를 줄여 성능을 개선할 수 있습니다.
-- 4
SELECT /*+ PARALLEL(2) NO_USE_PARTITION_WISE_GBY NO_GBY_PUSHDOWN */
c1, COUNT (*) AS cnt
FROM t1
GROUP BY c1;
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | | |
| 1 | PX COORDINATOR | | | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10001 | | | Q1,01 | P->S | QC (RAND) |
| 3 | HASH GROUP BY | | | | Q1,01 | PCWP | | -- !
| 4 | PX RECEIVE | | | | Q1,01 | PCWP | |
| 5 | PX SEND HASH | :TQ10000 | | | Q1,00 | P->P | HASH |
| 6 | PX BLOCK ITERATOR | | 1 | 10 | Q1,00 | PCWC | |
| 7 | TABLE ACCESS FULL| T1 | 1 | 10 | Q1,00 | PCWP | |
-----------------------------------------------------------------------------------------