Join Predicate Push Down (JPPD) 는 Group By 가 있는 View 도 침투 가능 (2)
외부 GROUP BY + 인라인 뷰 GROUP BY 의 2단 집계 패턴에서도 JPPD 가 동작합니다. ORDERS 의 20 행이 인라인 뷰 안으로 한 행씩 밀려 들어가 SORT GROUP BY 가 부서당 124 행만 다루도록 압축되는 예시입니다.
Join Predicate Push Down (JPPD) 는 Group By 가 있는 View 도 침투 가능 (2)
GROUP BY 가 있는 인라인 뷰는 물론, VIEW 내부에 DISTINCT 가 있어도 JPPD 가 동작합니다. 옵티마이저는 외부 join 술어를 뷰 안으로 밀어 넣어 집계 대상 행 수를 줄입니다.
핵심 정리
- GROUP BY 가 있는 view 에도 view 바깥의 조인 조건을 view 내부로 침투시킬 수 있습니다.
- 이런 식으로 VIEW 내부에 DISTINCT 가 있어도 JPPD 가 가능합니다.
쿼리
ORDERS (A) + 인라인 뷰 B (ORDER_ITEMS · PRODUCTS 의 GROUP BY) 를 NL 로 묶고, 외부에서 다시 GROUP BY 로 일별 / 상품명별 집계를 만드는 패턴입니다. 인라인 뷰 안의 B.ORDER_ID 가 외부 조인 키라는 점을 주목해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT /*+ LEADING(A B) NO_PUSH_PRED(B) */
TO_CHAR(A.ORDER_DATE, 'YYYYMMDD') ORDER_DATE
, B.PRODUCT_NAME
, SUM(B.SALES_AMT) SALES_AMT
FROM ORDERS A,
(SELECT /*+ NO_MERGE LEADING(B C) USE_NL(C) */
B.ORDER_ID, C.PRODUCT_NAME
, SUM(B.UNIT_PRICE*B.QUANTITY) SALES_AMT
FROM ORDER_ITEMS B,
PRODUCTS C
WHERE B.PRODUCT_ID = C.PRODUCT_ID
GROUP BY B.ORDER_ID, C.PRODUCT_NAME) B -- ← JPPD JOIN 조건절에 대한 GROUP BY
WHERE A.ORDER_ID = B.ORDER_ID
AND A.ORDER_DATE >= TO_DATE('20120701', 'YYYYMMDD')
AND A.ORDER_DATE < TO_DATE('20120701', 'YYYYMMDD')
AND A.EMPLOYEE_ID = 'E070'
GROUP BY TO_CHAR(A.ORDER_DATE, 'YYYYMMDD'), B.PRODUCT_ID;
실행 계획
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 121 | 313 | |
| 1 | HASH GROUP BY | | 1 | 121 | 313 | 1270K (0) |
| 2 | NESTED LOOPS | | 1 | 142 | 313 | |
| 3 | TABLE ACCESS BY INDEX ROWID | ORDERS | 1 | 20 | 22 | |
|* 4 | INDEX RANGE SCAN | IX_ORDERS_N2 | 1 | 20 | 3 | |
| 5 | VIEW PUSHED PREDICATE | | 20 | 124 | 291 | |
| 6 | SORT GROUP BY | | 20 | 124 | 291 | 2048 (0) |
| 7 | NESTED LOOPS | | 20 | 124 | 291 | |
| 8 | NESTED LOOPS | | 20 | 124 | 167 | |
| 9 | TABLE ACCESS BY INDEX ROWID | ORDER_ITEMS | 20 | 124 | 163 | |
|*10 | INDEX RANGE SCAN | IX_ORDER_ITEMS_PK | 20 | 124 | 42 | |
|*11 | INDEX UNIQUE SCAN | IX_PRODUCTS_PK | 124 | 124 | 4 | |
| 12 | TABLE ACCESS BY INDEX ROWID | PRODUCTS | 124 | 124 | 124 | |
-------------------------------------------------------------------------------------------------------
Id 5 의 VIEW PUSHED PREDICATE 가 핵심 포인트입니다. 외부 NL (Id 2) 의 안쪽 가지인 인라인 뷰 B 가 ORDERS 의 각 row (20 회 Starts) 마다 호출되며, 그때마다 외부 술어 A.ORDER_ID = B.ORDER_ID 가 뷰 안의 SORT GROUP BY (Id 6) 위로 밀려 들어가 부서당 필요한 124 행만 집계됩니다.
참조
- 같은 패턴의 LATERAL 재작성 —
e.department_id가 GROUP BY 키에서 사라지는 원리: Join Predicate Push Down (JPPD) 는 Group By 가 있는 View 도 침투 가능 (1)
외부 join 키와 일치하는 컬럼이 인라인 뷰의 GROUP BY 키에 있으면, JPPD 후 그 컬럼은 상수처럼 작동합니다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.