Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-024

정산 대사 화면이 하루치 137건에 139블록을 읽고, 일주일을 고르면 정산 테이블을 통째로 읽는다

중급INSERT한빛유통99 / 700

상황 ​

정산팀의 「일자별 정산 대사」는 정산일 하루(가끔 일주일)를 골라 그 기간의 정산 목록을 보여 준다. 월말에는 날짜를 바꿔 가며 하루 수천 번 연다. 정산 테이블은 야간 배치가 매일 밤 비우고(TRUNCATE) 주문 테이블에서 한 문장으로 다시 채운다. 조민우는 "정산일 인덱스를 만들었는데 효과가 없다. 매일 밤 적재가 끝나면 인덱스를 REBUILD하자"고 한다. 아래는 2024-06-14 하루와 2024-06-10 ~ 06-16 일주일이다.

테이블과 인덱스 ​

  • T_ORD(원천): 100,000행 · 896블록 · ORD_SEQ 순으로 쌓였다 · ORD_DT DATE(시분초 있음, 2023 ~ 2024) · ORD_DT는 주문 번호와 상관없이 730일을 돌아가며 붙어 있어, 같은 날짜의 주문은 ORD_SEQ가 730씩 떨어져 있다
  • T_ORD_STLM 정산: 100,000행 · 640블록(블록당 약 156행) · 주문 한 건에 정산 한 건 · STLM_DT는 ORD_DT를 그대로 옮긴 값 · 하루 137건 · 일주일 959건
  • 인덱스 IX_STLM_DT (STLM_DT): BLEVEL 1 · 리프 약 270블록 · CLUSTERING_FACTOR 99,986 · IX_STLM_CUS (CUS_ID): 「고객별 정산 내역」용 · CLUSTERING_FACTOR 약 100,000 · 통계는 적재 뒤에 수집한다
  • STLM_SEQ(정산 번호)는 지금 주문 번호 순서와 같다 · 정산 번호로 대사표를 맞추는 보고서가 있다 · DB는 NOARCHIVELOG

원본 SQL ​

sql
-- 야간 적재 (매일 밤, TRUNCATE 뒤)
INSERT /*+ APPEND */ INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
SELECT ROWNUM, ORD_SEQ, CUS_ID, ORD_DT, ORD_AMT
  FROM T_ORD;
COMMIT;

-- 「일자별 정산 대사」
SELECT STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT
  FROM T_ORD_STLM
 WHERE STLM_DT >= TO_DATE(:v_from, 'YYYYMMDD')
   AND STLM_DT <  TO_DATE(:v_to, 'YYYYMMDD') + 1
 ORDER BY STLM_DT, ORD_SEQ;

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 ​

xplan
[대사 · 하루 2024-06-14]
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |            |      1 |        |    137 |00:00:00.01 |     139 |          |
|   1 |  SORT ORDER BY                        |            |      1 |    137 |    137 |00:00:00.01 |     139 |   18432 |
|*  2 |   FILTER                              |            |      1 |        |    137 |00:00:00.01 |     139 |          |
|   3 |    TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD_STLM |      1 |    137 |    137 |00:00:00.01 |     139 |          |
|*  4 |     INDEX RANGE SCAN                  | IX_STLM_DT |      1 |    137 |    137 |00:00:00.01 |       2 |          |
------------------------------------------------------------------------------------------------------------------
   2 - filter(TO_DATE(:V_TO,'YYYYMMDD')+1>TO_DATE(:V_FROM,'YYYYMMDD'))
   4 - access("STLM_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND "STLM_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1)

[대사 · 일주일 2024-06-10 ~ 06-16]
------------------------------------------------------------------------------------------------------------------
| Id  | Operation                             | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                      |            |      1 |        |    959 |00:00:00.01 |     640 |          |
|   1 |  SORT ORDER BY                        |            |      1 |    959 |    959 |00:00:00.01 |     640 |  124K   |
|*  2 |   FILTER                              |            |      1 |        |    959 |00:00:00.01 |     640 |          |
|*  3 |    TABLE ACCESS FULL                  | T_ORD_STLM |      1 |    959 |    959 |00:00:00.01 |     640 |          |
------------------------------------------------------------------------------------------------------------------
   3 - filter(("STLM_DT">=TO_DATE(:V_FROM,'YYYYMMDD') AND "STLM_DT"<TO_DATE(:V_TO,'YYYYMMDD')+1))

[USER_INDEXES · USER_TABLES]  IX_STLM_DT  CLUSTERING_FACTOR 99,986 · T_ORD_STLM BLOCKS 640 · NUM_ROWS 100,000

문제 ​

  1. 하루치 137건에 테이블을 137블록 읽는 이유를 CLUSTERING_FACTOR와 야간 적재 SQL로 설명하시오. 일주일이면 옵티마이저가 FULL로 바꾸는 이유와, REBUILD 제안이 효과가 있는지도 설명하시오.
  2. 대사 화면 SQL은 그대로 두고 적재를 고쳐 하루치가 몇 블록으로 끝나게 하시오. 정산 번호(STLM_SEQ)의 뜻이 바뀌지 않게 하고, 고친 적재의 대가를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자