테마
POS 테이블에 비트맵 인덱스를 만들었다가 점심 결제가 멈춘 일 뒤로, 버거 본사 BI팀은 매일 밤 리포트용 마트 DW_ORD_ITEM을 따로 만들어 리포트를 그쪽으로 옮겼다. BI팀은 요청이 올 때마다 마트에 B-tree 인덱스를 하나씩 만들어 지금 셋이다.
그런데 BI 도구의 자유 조합 리포트(S1)는 여전히 마트를 통째로 읽고, 점장 리포트(S2)도 700블록 넘게 읽는다. 박팀장은 "마트의 인덱스를 처음부터 다시 설계하고 밤 적재 절차까지 적어 와라"고 했다.
DW_ORD_ITEM 주문상품 리포트 마트: 매일 02:00에 TRUNCATE 뒤 ORD_ITEM · ORD · SHOP · ITEM을 조인해 INSERT /*+ APPEND */로 다시 채운다 · 낮에는 읽기만 한다 · 2,472,717행 · 15,200블록 · ORD_DT 순으로 쌓인다ORD_NO(약 100만 가지) · ORD_DT VARCHAR2(8) 730일 · ORD_HH 14가지(09 ~ 22시, 고르게) · DOW_CD 7가지 · SHOP_NO 200곳 · RGN_CD 8곳(매장이 고르게 나뉜다) · ITEM_ID 92가지 · ITEM_TYPE_CD 여러 분류(버거 '100100'이 18종, 약 20%) · ORD_ITEM_QTYDW_OI_X01 (ORD_DT, SHOP_NO) · DW_OI_X02 (ITEM_ID, ORD_DT) · DW_OI_X03 (RGN_CD, ITEM_TYPE_CD) · 리프는 각각 약 9,200 · 9,200 · 7,100블록-- S1 자유 조합 리포트 (BI 도구가 고른 조건만 WHERE에 붙인다 · 아래는 한 예)
SELECT ITEM_ID, SUM(ORD_ITEM_QTY) AS qty, COUNT(*) AS line_cnt
FROM DW_ORD_ITEM
WHERE RGN_CD = :v_rgn
AND ITEM_TYPE_CD = '100100'
AND DOW_CD IN ('1', '7')
AND ORD_HH BETWEEN '11' AND '13'
GROUP BY ITEM_ID;
-- S2 점장 리포트 : 매장 하나의 한 달 일별 메뉴 판매
SELECT ORD_DT, ITEM_ID, SUM(ORD_ITEM_QTY) AS qty
FROM DW_ORD_ITEM
WHERE SHOP_NO = :v_shop
AND ORD_DT BETWEEN :v_from AND :v_to
GROUP BY ORD_DT, ITEM_ID;
-- S3 고객센터 : 주문 한 건의 상품
SELECT ITEM_ID, ORD_ITEM_QTY FROM DW_ORD_ITEM WHERE ORD_NO = :v_ord_no;
-- 밤 적재 (02:00)
TRUNCATE TABLE DW_ORD_ITEM;
INSERT /*+ APPEND */ INTO DW_ORD_ITEM
SELECT ... ;
COMMIT;
[S1 · 한 지역 · 버거 · 주말 · 11 ~ 13시]
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 18 |00:00:00.21 | 15200 |
| 1 | HASH GROUP BY | | 1 | 18 | 18 |00:00:00.21 | 15200 |
|* 2 | TABLE ACCESS FULL | DW_ORD_ITEM | 1 | 3705 | 3705 |00:00:00.20 | 15200 |
-------------------------------------------------------------------------------------------------------------
2 - filter(("RGN_CD"=:V_RGN AND "ITEM_TYPE_CD"='100100' AND INTERNAL_FUNCTION("DOW_CD")
AND "ORD_HH">='11' AND "ORD_HH"<='13'))
[S2 · SH0042 · 2013년 11월]
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 488 |00:00:00.02 | 737 |
| 1 | HASH GROUP BY | | 1 | 515 | 488 |00:00:00.02 | 737 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| DW_ORD_ITEM | 1 | 515 | 515 |00:00:00.02 | 737 |
|* 3 | INDEX RANGE SCAN | DW_OI_X01 | 1 | 515 | 515 |00:00:00.01 | 385 |
-------------------------------------------------------------------------------------------------------------
3 - access("ORD_DT">=:V_FROM AND "SHOP_NO"=:V_SHOP AND "ORD_DT"<=:V_TO)
filter("SHOP_NO"=:V_SHOP)