Skip to content
튜닝 연습소트 튜닝과 페이징
SORT-037

PG사 요청으로 정산 파일 레코드를 300바이트로 늘린 뒤부터 추출 배치가 TEMP를 쓴다

중급SELECT한빛유통342 / 700

상황 ​

매월 1일 03시에 도는 「PG 대사 파일 추출」은 그해 1월 1일부터 지난달 말까지의 구매 완료 주문을 주문번호순으로 고정 길이 레코드로 만들어 파일로 내린다. 지난달 PG사가 레코드 형식을 100바이트에서 300바이트(뒤쪽 207바이트는 예비 영역 공백)로 바꿔 달라고 했고, 개발자는 SQL의 마지막 RPAD 하나만 고쳤다. 이번 달 1일 추출은 0.9초에서 4.1초로 늘었고 TEMP를 85MB 썼다. 같은 시각에 다른 배치들이 돌아 work area 하나의 상한은 약 40MB다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_SEQ NUMBER(유일) · CUS_ID 'CUS_000123' · ORD_DT DATE(전부 자정) · ORD_ST(COMPLETE 90%) · ORD_AMT
  • 2024-01-01 ~ 2024-11-30의 구매 완료 주문은 275,089건이다(테이블의 약 28%). 이 범위를 읽기에 알맞은 인덱스는 없고, ORD_SEQ로 시작하는 인덱스도 없다.
  • 파일의 레코드는 주문번호순이어야 한다(PG사 대사 규약). 통계는 최신이다.

원본 SQL ​

sql
SELECT RPAD(TO_CHAR(ORD_SEQ), 20)
    || RPAD(CUS_ID, 40)
    || TO_CHAR(ORD_DT, 'YYYYMMDD')
    || LPAD(TO_CHAR(ORD_AMT), 15, '0')
    || RPAD(ORD_ST, 10)
    || RPAD(' ', 207) AS REC
  FROM T_ORD_BIG
 WHERE ORD_DT >= DATE '2024-01-01'
   AND ORD_DT <  DATE '2024-12-01'
   AND ORD_ST = 'COMPLETE'
 ORDER BY ORD_SEQ

실행계획 학습용 예시 ​

xplan
[이번 달 1일 03:00 · 레코드 300바이트]
-----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem | Used-Tmp|
-----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |      1 |        |    275K|00:00:04.12 |    5833 |       |       |          |         |
|   1 |  SORT ORDER BY     |           |      1 |    275K|    275K|00:00:04.12 |    5833 |    86M|  2654K|   40M (1)|      85M|
|*  2 |   TABLE ACCESS FULL| T_ORD_BIG |      1 |    275K|    275K|00:00:00.16 |    5826 |       |       |          |         |
-----------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(("ORD_ST"='COMPLETE' AND "ORD_DT">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "ORD_DT"<TO_DATE(' 2024-12-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))

[지난달 1일 · 레코드 100바이트]  1번 줄 OMem 31M · Used-Mem 28M (0) · Used-Tmp 없음 · A-Time 0.9초

문제 ​

  1. 레코드 길이 하나를 바꿨을 뿐인데 정렬에 드는 메모리가 31MB에서 86MB로 늘어난 까닭을 정렬이 줄 세우는 행의 모양으로 설명하시오.
  2. 파일 내용과 순서가 바뀌지 않게 SQL을 고쳐 정렬이 다시 메모리 안에서 끝나게 하고, 고친 SQL이 의도대로 돌았는지 실행계획의 어느 줄로 확인할지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자