테마
한빛유통 DBA가 분기 점검에서 '접두 중복 인덱스' 찾기 스크립트를 돌렸다. 스크립트의 규칙은 이렇다. "한 인덱스의 컬럼이 다른 인덱스의 앞부분과 같으면 짧은 쪽을 지운다." 스크립트가 지울 목록 넷과 DROP 문을 만들었고, DBA는 이번 주 토요일에 그대로 돌릴 생각이다. 박팀장은 이렇게 적어 보냈다. "넷을 하나씩 따져 오고, 실제로 정리할 인덱스와 스크립트 규칙을 고쳐 와라."
T_ORD 주문: 100,000행 · 896블록 · 주문 INSERT 하루 약 140건 · 결제나 취소로 ORD_ST를 고치는 UPDATE 하루 약 300건
PK_T_ORD (ORD_SEQ): PK 제약을 받치는 유니크 인덱스 · BLEVEL 1 · 리프 약 190블록IX_T_ORD_SEQ_ST (ORD_SEQ, ORD_ST): 2019년 「주문 상태 확인」 API(SELECT ORD_ST FROM T_ORD WHERE ORD_SEQ = :o, 하루 약 5만 번)를 테이블에 가지 않게 하려고 만들었다 · 리프 약 240블록IX_T_ORD_CUS (CUS_ID): 리프 약 330블록 · IX_T_ORD_CUS_DT (CUS_ID, ORD_DT): 상담 화면용 · 리프 약 375블록 · FK FK_ORD_CUS (CUS_ID → M_CUS)T_ORD_DET 주문상세: 200,000행 · 896블록 · (ORD_SEQ, ORD_DET_NO) 순으로 쌓였다 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO): BLEVEL 1 · 리프 약 500블록 · IX_T_ORD_DET_SEQ (ORD_SEQ): 리프 약 400블록 · FK FK_ORD_DET_ORD (ORD_SEQ → T_ORD)T_ORD_STLM 정산: 100,000행 · 640블록 · 야간 배치가 비우고(TRUNCATE) 주문 한 건에 정산 한 건씩 다시 채운다
UX_STLM_ORD (ORD_SEQ): 제약 없이 CREATE UNIQUE INDEX로 만든 유니크 인덱스 · 2022년 정산 배치가 두 번 돌아 정산이 두 배로 찍힌 사고 뒤에 만들었다IX_STLM_ORD_DT (ORD_SEQ, STLM_DT): 「PG 대사」 배치용(SELECT STLM_SEQ, STLM_AMT … WHERE ORD_SEQ = :o AND STLM_DT >= :d)-- 스크립트가 만든 DROP 문 (이번 주 토요일 실행 예정)
DROP INDEX IX_T_ORD_DET_SEQ; -- ① (ORD_SEQ) ⊂ PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO)
DROP INDEX PK_T_ORD; -- ② (ORD_SEQ) ⊂ IX_T_ORD_SEQ_ST (ORD_SEQ, ORD_ST)
DROP INDEX IX_T_ORD_CUS; -- ③ (CUS_ID) ⊂ IX_T_ORD_CUS_DT (CUS_ID, ORD_DT)
DROP INDEX UX_STLM_ORD; -- ④ (ORD_SEQ) ⊂ IX_STLM_ORD_DT (ORD_SEQ, STLM_DT)
-- 참고: 「주문 상태 확인」 API
SELECT ORD_ST FROM T_ORD WHERE ORD_SEQ = :o;
[「주문 상태 확인」 API · 지금]
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 2 |
|* 1 | INDEX RANGE SCAN| IX_T_ORD_SEQ_ST | 1 | 1 | 1 |00:00:00.01 | 2 |
---------------------------------------------------------------------------------------------
1 - access("ORD_SEQ"=:O)
[같은 API · NO_INDEX(T_ORD IX_T_ORD_SEQ_ST) 힌트로 잰 것]
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 3 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_ORD | 1 | 1 | 1 |00:00:00.01 | 3 |
|* 2 | INDEX UNIQUE SCAN | PK_T_ORD | 1 | 1 | 1 |00:00:00.01 | 2 |
----------------------------------------------------------------------------------------------
2 - access("ORD_SEQ"=:O)
[주문 상세 조회 WHERE ORD_SEQ = :o] 지금 IX_T_ORD_DET_SEQ로 Buffers 3 · NO_INDEX 힌트로 PK_T_ORD_DET를 쓰게 해도 Buffers 3