테마
버거원 DBA 오과장이 분기 인덱스 점검에서 주문 테이블의 ORD_X05를 정리하자고 올렸다. 작년에 개발자가 본사 「매장별 오늘 주문」(S3)의 정렬을 없애겠다며 만든 내림차순 인덱스다. 장애 뒤 재적재 때마다 인덱스 하나만큼 시간과 redo가 더 든다는 것이 이유다.
조민우는 반대했다. "V$SQL_PLAN을 보니 점주 앱 「최근 주문 20건」(S1)이 하루 4만 번 X05를 씁니다. 지우면 점주 앱이 매번 정렬을 하게 됩니다." 박팀장은 둘 중 누구 말이 맞는지 숫자로 판정해 오라고 했다.
ORD 주문: 1,000,000행 · 22,422블록 · 주문 일시 순으로 쌓였다(하루치가 약 31블록 안에 모여 있다) · ORD_NO · ORD_DT VARCHAR2(8) · ORD_HMS VARCHAR2(6) · SHOP_NO VARCHAR2(10) 200곳 · 하루 약 1,370건, 매장 하나의 하루 주문은 평균 7건ORD_PK (ORD_NO)ORD_X01 (ORD_DT, ORD_HMS): 리프 3,774블록ORD_X02 (SHOP_NO, ORD_DT, ORD_HMS): 점주 앱용 · 리프 약 4,050블록ORD_X05 (SHOP_NO, ORD_DT DESC, ORD_HMS DESC): 작년에 S3용으로 만든 내림차순 인덱스 · 리프 약 4,050블록 · CF도 ORD_X02와 같다-- S1 점주 앱 「최근 주문 20건」 (하루 약 4만 번)
SELECT ORD_NO, ORD_DT, ORD_HMS
FROM ORD
WHERE SHOP_NO = :v_shop
ORDER BY ORD_DT DESC, ORD_HMS DESC
FETCH FIRST 20 ROWS ONLY;
-- S2 점주 앱 「기간 주문 목록」 (하루 수천 번)
SELECT ORD_NO, ORD_DT, ORD_HMS
FROM ORD
WHERE SHOP_NO = :v_shop
AND ORD_DT BETWEEN :v_from AND :v_to
ORDER BY ORD_DT, ORD_HMS;
-- S3 본사 「매장별 오늘 주문」 (본사 PC 10대가 5분마다)
SELECT SHOP_NO, ORD_HMS, ORD_NO
FROM ORD
WHERE ORD_DT = :v_dt
ORDER BY SHOP_NO, ORD_HMS DESC;
-- 작년에 S3 의 정렬을 없애려고 만든 인덱스
CREATE INDEX ORD_X05 ON ORD (SHOP_NO, ORD_DT DESC, ORD_HMS DESC);
[S1 · 지금 · SH0042]
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.01 | 24 |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.01 | 24 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 20 | 20 |00:00:00.01 | 24 |
| 3 | TABLE ACCESS BY INDEX ROWID | ORD | 1 | 20 | 20 |00:00:00.01 | 24 |
|* 4 | INDEX RANGE SCAN | ORD_X05 | 1 | 20 | 20 |00:00:00.01 | 4 |
----------------------------------------------------------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=20)
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("ORD_DT") DESC ,INTERNAL_FUNCTION("ORD_HMS") DESC )<=20)
4 - access("SHOP_NO"=:V_SHOP)
[S3 · 지금 · 2013-03-15]
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1370 |00:00:00.01 | 38 | |
| 1 | SORT ORDER BY | | 1 | 1370 | 1370 |00:00:00.01 | 38 | 83K |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED | ORD | 1 | 1370 | 1370 |00:00:00.01 | 38 | |
|* 3 | INDEX RANGE SCAN | ORD_X01 | 1 | 1370 | 1370 |00:00:00.01 | 7 | |
----------------------------------------------------------------------------------------------------------------------
3 - access("ORD_DT"=:V_DT)
[S3 · 같은 날 · INDEX_SS(ORD ORD_X05) 힌트로 잰 것]
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1370 |00:00:00.03 | 1968 |
| 1 | TABLE ACCESS BY INDEX ROWID | ORD | 1 | 1370 | 1370 |00:00:00.03 | 1968 |
|* 2 | INDEX SKIP SCAN | ORD_X05 | 1 | 1370 | 1370 |00:00:00.01 | 598 |
--------------------------------------------------------------------------------------------------
2 - access(SYS_OP_DESCEND("ORD_DT")=SYS_OP_DESCEND(:V_DT))
filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("ORD_DT"))=:V_DT)
[V$SQL_PLAN · 지난 2주] ORD_X05를 쓰는 SQL은 S1 하나다 · S2는 ORD_X02를 쓰고, S3는 늘 ORD_X01과 SORT ORDER BY다
ORD_X05를 지우면 S1이 정렬을 한다)가 맞는지 S1의 조건과 ORD_X02의 컬럼 순서로 판정하시오.ORD_X05를 만든 본래 목적(S3의 정렬 없애기)이 맞는 판단이었는지 두 계획의 숫자로 설명하시오.ORD_X05를 정리하는 DDL을 작성하고, 지우기 전에 확인할 것과 지워서 얻는 것을 설명하시오.