테마
CRM팀의 「VIP 기간 실적」은 2024년에 A 등급이던 동안의 주문만 골라 고객별 건수와 금액을 낸다. 연말 감사 선물 대상을 확정하는 기간이라 하루 수십 번 돌리는데, 한 번에 4.6초가 걸린다.
SQL은 사내 템플릿대로 "주문을 먼저 읽고, 등급 이력은 PK로 붙인다"(LEADING(o h) USE_NL(h))는 힌트를 달았다. 같은 템플릿으로 만든 「일자별 주문 목록」(날짜 하나를 고르면 그날 주문 913건에 주문 당시 등급을 붙인다)은 0.01초라서, 개발자는 템플릿 탓이 아니라고 한다.
T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_DT는 전부 자정 · 2024년 주문 333,245건 · 고객마다 하루 평균 0.46건IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT, ORD_AMT): 작년에 「지역별 고객 월 매출」 화면 때문에 만들었다 · 높이 3 · 리프 약 3,400블록M_CUS_GD_HIS 고객 등급 이력 (이 문제에서 쓰는 파생 테이블, 선분이력): CUS_ID · ST_DT · ED_DT (그날까지 포함, 지금 구간은 DATE '9999-12-31') · CUS_GD · 2022년부터 분기마다 재산정하고 등급이 바뀐 고객만 새 구간을 연다 · 6,140행 · 40블록 · PK_M_CUS_GD_HIS (CUS_ID, ST_DT) (BLEVEL 1)SELECT /*+ LEADING(o h) USE_NL(h) */
o.CUS_ID, COUNT(*) AS ord_cnt, SUM(o.ORD_AMT) AS ord_amt
FROM T_ORD_BIG o, M_CUS_GD_HIS h
WHERE o.ORD_DT >= DATE '2024-01-01'
AND o.ORD_DT < DATE '2025-01-01'
AND h.CUS_ID = o.CUS_ID
AND o.ORD_DT BETWEEN h.ST_DT AND h.ED_DT
AND h.CUS_GD = 'A'
GROUP BY o.CUS_ID
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 31 |00:00:04.62 | 1339K|
| 1 | HASH GROUP BY | | 1 | 31 | 31 |00:00:04.62 | 1339K|
| 2 | NESTED LOOPS | | 1 | 1667 | 2006 |00:00:04.59 | 1339K|
| 3 | NESTED LOOPS | | 1 | 833K| 832K|00:00:01.71 | 672K|
|* 4 | TABLE ACCESS FULL | T_ORD_BIG | 1 | 333K| 333K|00:00:00.06 | 5826 |
|* 5 | INDEX RANGE SCAN | PK_M_CUS_GD_HIS | 333K| 3 | 832K|00:00:01.32 | 666K|
|* 6 | TABLE ACCESS BY INDEX ROWID| M_CUS_GD_HIS | 832K| 1 | 2006 |00:00:02.61 | 667K|
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter(("O"."ORD_DT">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"O"."ORD_DT"<TO_DATE(' 2025-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
5 - access("H"."CUS_ID"="O"."CUS_ID" AND "H"."ST_DT"<="O"."ORD_DT")
6 - filter(("H"."CUS_GD"='A' AND "H"."ED_DT">="O"."ORD_DT"))
Starts와 5번, 6번 줄의 Predicate Information으로 설명하시오.BETWEEN 조건이 어느 인덱스의 access 조건이 되는지도 설명하시오.