Skip to content
튜닝 연습파티션
PART-044

세금계산서 판매만 5년 남기라는 규정 때문에 2만 행 DELETE가 매달 redo 9MB를 쓴다

중급DELETE유통419 / 700

상황 ​

유통 본사의 판매 보관 기준은 24개월이다. 다만 세금계산서를 발행한 법인 판매는 세법에 따라 5년을 보관해야 한다. 그래서 매월 1일 01:00 「보관 정리」는 24개월이 지난 달의 칸을 통째로 들어내지 못하고, 법인 판매를 뺀 나머지를 DELETE로 지운다. 이번 달 대상은 2022년 1월이다. 정리한 칸에는 행이 3%만 남는데 FULL로 읽으면 그대로 191블록이고, 정리하는 밤마다 redo가 9MB 넘게 나온다. 법인 여부는 판매 테이블의 컬럼이 아니라 세금계산서 테이블에 있어서 칸 기준으로 삼을 수도 없다. 박팀장: "남길 행이 있어도 칸 단위로 처리할 방법을 찾아 봐."

테이블과 인덱스 ​

  • CF10_P 판매(파티션 복사본, 문제 설정): CF10 500,000행을 PARTITION BY RANGE (SLE_DT) 월별 24칸(P202201 ~ P202312)과 빈 PMAX로 나눴다. 컬럼은 SLE_NO · SLE_DT · SLE_HMS · SLE_DOW · SHP_NO다. P202201은 1번째 칸이고 20,831행, FULL로 191블록(세그먼트 8MB)이다.
  • LOCAL 인덱스 둘: PK CF10_P_PK (SLE_NO, SLE_DT) 유니크 · CF10_P_X01 (SHP_NO, SLE_DT). GLOBAL 인덱스, FK, 트리거는 없다.
  • CF10_TAX 세금계산서 발행 판매(문제 설정): 14,880행 · SLE_NO · TAX_NO · ISS_DT · PK CF10_TAX_PK (SLE_NO). 판매의 약 3%이고, 2022년 1월 판매 중에서는 624건이다.
  • 판매상품 CF11의 정리는 다른 단계에서 한다(이 문제에서는 다루지 않는다). 운영은 ARCHIVELOG다. 정리 시각(01:00 ~ 01:30)에 이 칸을 읽거나 고치는 다른 작업은 없다.

원본 SQL ​

sql
-- 매월 1일 01:00 · 24개월이 지난 달 정리 (이번 달 = 2022년 1월)
DELETE FROM CF10_P s
 WHERE s.SLE_DT >= '20220101'
   AND s.SLE_DT <  '20220201'
   AND NOT EXISTS (SELECT 1 FROM CF10_TAX t WHERE t.SLE_NO = s.SLE_NO);
COMMIT;

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name        | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
-------------------------------------------------------------------------------------------------------------------
|   0 | DELETE STATEMENT          |             |      1 |        |      0 | 00:00:00.71 |   63412 |        |       |
|   1 |  DELETE                   | CF10_P      |      1 |        |      0 | 00:00:00.71 |   63412 |        |       |
|*  2 |   HASH JOIN RIGHT ANTI    |             |      1 |  20207 |  20207 | 00:00:00.04 |     253 |        |       |
|   3 |    INDEX FAST FULL SCAN   | CF10_TAX_PK |      1 |  14880 |  14880 | 00:00:00.01 |      62 |        |       |
|   4 |    PARTITION RANGE SINGLE |             |      1 |  20831 |  20831 | 00:00:00.01 |     191 |      1 |     1 |
|*  5 |     TABLE ACCESS FULL     | CF10_P      |      1 |  20831 |  20831 | 00:00:00.01 |     191 |      1 |     1 |
-------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T"."SLE_NO"="S"."SLE_NO")
   5 - filter(("S"."SLE_DT">='20220101' AND "S"."SLE_DT"<'20220201'))

[세션 통계 · DELETE + COMMIT]
  지운 행 20,207 · redo size 약 9.4 MB · undo change vector size 약 4.6 MB · db block changes 약 61,000

[정리 뒤 · P202201]
  남은 행 624 · FULL Buffers 191 그대로 · 세그먼트 8 MB 그대로 · 두 인덱스 칸의 리프 블록 수도 그대로

문제 ​

  1. 지금 DELETE의 비용이 어디서 나오는지, 정리한 칸이 왜 그대로 191블록인지 설명하시오.
  2. 남길 법인 판매 624건은 지키면서 행을 하나씩 지우지 않도록, 칸 단위 작업으로 정리 SQL을 다시 작성하시오.
  3. 남길 행을 따로 빼 두고 칸을 TRUNCATE한 뒤 다시 넣는 방법과 비교해 고른 방법이 나은 까닭을 쓰고, 이 방법이 맞지 않는 경우도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자