테마
버거 본사 IT가 분석 DB의 주문 사본을 다시 지으려 한다. 매장 관리자 화면이 가장 자주 도니 매장마다 월마다 조각을 따로 두자는 안 (나)가 올라왔다. "매장 화면이 조각 하나만 읽으니 제일 빠르다." 오과장은 월 한 단계 안 (가)와 매장 해시 안 (다)를 함께 비교해 보자고 했다. 분석 DB에는 지난해 월 정리 뒤 GLOBAL 인덱스가 UNUSABLE이 된 장애 이후로 "GLOBAL 인덱스를 두지 않는다"는 운영 규칙이 있다.
ORD_LIST(교재 14화): 주문 1,000,000행 · PARTITION BY LIST (ORD_YM) 24칸 · 빈 테이블에 APPEND로 채워 칸 하나 FULL ≈ 1,980블록. ORD_RANDOM에서 적재해 행이 매장끼리 섞여 있다(매장 하나의 한 달 205건이 거의 모두 다른 블록에 있다).SHOP_NO와 ORD_YM(하루 약 3,000번) · Q2 「월 매장 실적」 ORD_YM 전 매장(하루 약 30번) · Q3 「영수증 조회」 ORD_NO와 ORD_YM(하루 약 6만 번) · Q4 「월 정리」 24개월 지난 달을 들어낸다(월 1회) · Q5 「폐점 매장 정리」 폐점 매장의 주문을 지운다(한 해 몇 번)LIST (ORD_YM) 월 한 단계 + LOCAL PK (ORD_NO, ORD_YM) + LOCAL 인덱스 (SHOP_NO, ORD_DT, ORD_HMS)LIST (ORD_YM) × LIST (SHOP_NO) 매장마다 한 조각(200개와 DEFAULT) · 서브파티션 키가 없는 (ORD_NO, ORD_YM)은 LOCAL 유니크가 될 수 없어 LOCAL 일반 인덱스 (ORD_NO)를 둔다LIST (ORD_YM) × HASH (SHOP_NO) 8조각 · 인덱스는 (나)와 같다STORAGE (INITIAL 64K)로 짓는다.-- Q1 「매장 주문 내역」
SELECT ORD_NO, ORD_DT, ORD_HMS
FROM ORD_LIST
WHERE SHOP_NO = :v_shop
AND ORD_YM = :v_ym
ORDER BY ORD_DT, ORD_HMS;
-- Q2 「월 매장 실적」
SELECT SHOP_NO, COUNT(*) AS ord_cnt
FROM ORD_LIST
WHERE ORD_YM = :v_ym
GROUP BY SHOP_NO;
-- Q3 「영수증 조회」
SELECT ORD_NO, ORD_YM, ORD_DT, ORD_HMS, SHOP_NO
FROM ORD_LIST
WHERE ORD_NO = :ord_no
AND ORD_YM = :ord_ym;
-- Q4 「월 정리」
ALTER TABLE ORD_LIST DROP PARTITION P201201;
-- Q5 「폐점 매장 정리」
DELETE FROM ORD_LIST WHERE SHOP_NO = :v_closed_shop;
[지금 ORD_LIST · Q1 · SH0042 · 201306]
----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Pstart | Pstop |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 207 | 00:00:00.03 | 1980 | | |
| 1 | SORT ORDER BY | | 1 | 205 | 207 | 00:00:00.03 | 1980 | | |
| 2 | PARTITION LIST SINGLE | | 1 | 205 | 207 | 00:00:00.03 | 1980 | KEY | KEY |
|* 3 | TABLE ACCESS FULL | ORD_LIST | 1 | 205 | 207 | 00:00:00.03 | 1980 | KEY | KEY |
----------------------------------------------------------------------------------------------------------------
3 - filter(("SHOP_NO"=:V_SHOP AND "ORD_YM"=:V_YM))
[시험 DB · (나) · Q1]
--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Pstart | Pstop |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 207 | 00:00:00.01 | 6 | | |
| 1 | SORT ORDER BY | | 1 | 205 | 207 | 00:00:00.01 | 6 | | |
| 2 | PARTITION LIST SINGLE | | 1 | 205 | 207 | 00:00:00.01 | 6 | KEY | KEY |
| 3 | PARTITION LIST SINGLE | | 1 | 205 | 207 | 00:00:00.01 | 6 | KEY | KEY |
| 4 | TABLE ACCESS FULL | ORD_LIST_SS | 1 | 205 | 207 | 00:00:00.01 | 6 | KEY | KEY |
--------------------------------------------------------------------------------------------------------------------
[시험 DB · (나) · Q3 · 777777 · 201307]
--------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Pstart | Pstop |
--------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 | 00:00:00.01 | 201 | | |
| 1 | PARTITION LIST SINGLE | | 1 | 1 | 1 | 00:00:00.01 | 201 | KEY | KEY |
| 2 | PARTITION LIST ALL | | 1 | 1 | 1 | 00:00:00.01 | 201 | 1 | 201 |
| 3 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED | ORD_LIST_SS | 200 | 1 | 1 | 00:00:00.01 | 201 | KEY | KEY |
|* 4 | INDEX RANGE SCAN | ORD_LIST_SS_X01 | 200 | 1 | 1 | 00:00:00.01 | 200 | KEY | KEY |
--------------------------------------------------------------------------------------------------------------------------------------------
4 - access("ORD_NO"=:ORD_NO)
[시험 DB · 세그먼트] (가) 24개 · (나) 4,800개 · (다) 192개