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

야간 TEMP를 줄이려는 적재 정리안을 개발 서버에 먼저 넣었더니 메뉴별 판매 추이 화면이 45배 무거워졌다

중급INSERT유통345 / 700

상황 ​

지난달 03시에 배치 하나가 ORA-01652로 멈춘 뒤, DBA는 "힙 테이블은 넣은 순서를 약속하지 않으니 적재 SELECT의 ORDER BY는 정렬만 늘린다"며 야간 INSERT … SELECT에서 ORDER BY를 일괄로 지우는 정리안을 올렸다. 목록에는 MD팀의 분석 사본 CF11_ANL을 채우는 적재도 들어 있다. 정리안을 개발 서버에 먼저 넣고 다음 날 아침 MD팀 화면을 재 보니, 「메뉴별 일 판매 추이」가 메뉴 하나 한 해에 81블록이던 것이 3,689블록이 됐다. MD팀 20명이 하루 약 1,500번 여는 화면이다. 적재 SQL의 ORDER BY 옆에는 아무 주석도 없다.

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · 4,583블록 / CF11 판매상품: 1,096,708행 · 8,204블록 · 둘 다 판매번호(곧 판매일) 순으로 쌓여 있다
  • CF11_ANL 분석 사본(이 문제에서 쓰는 표): ITM_NO · SLE_DT · SLE_NO · SHP_NO · SLE_QTY · SLE_UPRC · 1,096,708행 · 10,240블록(블록당 약 107행) · 03:00에 TRUNCATE한 뒤 APPEND로 다시 채운다 · MD팀 화면만 읽는다
  • 인덱스 CF11_ANL_X01 (ITM_NO, SLE_DT): 리프 약 3,100블록 · CLUSTERING_FACTOR는 운영 10,262, 정리안대로 적재한 개발 서버 641,880
  • work area 하나의 상한(global memory bound)은 03:00에 약 20MB다. 02:30에는 TEMP를 많이 쓰는 다른 두 배치가 아직 돌지 않아 약 100MB다. 통계는 적재 뒤에 수집한다.

원본 SQL ​

sql
-- 정리안 : 03:00 분석 사본 적재에서 ORDER BY d.ITM_NO, h.SLE_DT, d.SLE_NO 를 지운 판
INSERT /*+ APPEND */ INTO CF11_ANL (ITM_NO, SLE_DT, SLE_NO, SHP_NO, SLE_QTY, SLE_UPRC)
SELECT d.ITM_NO, h.SLE_DT, d.SLE_NO, h.SHP_NO, d.SLE_QTY, d.SLE_UPRC
  FROM CF10 h, CF11 d
 WHERE d.SLE_NO = h.SLE_NO;

-- MD 「메뉴별 일 판매 추이」
SELECT SLE_DT, SUM(SLE_QTY) AS QTY, SUM(SLE_QTY * SLE_UPRC) AS AMT
  FROM CF11_ANL
 WHERE ITM_NO = :itm
   AND SLE_DT BETWEEN :d_from AND :d_to
 GROUP BY SLE_DT
 ORDER BY SLE_DT;

실행계획 학습용 예시 ​

xplan
[운영 · 지금 적재 (ORDER BY 있음) · 03:00]
-----------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem | Used-Tmp|
-----------------------------------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT                 |          |      1 |        |      0 |00:00:09.62 |   13204 |       |       |          |         |
|   1 |  LOAD AS SELECT                  | CF11_ANL |      1 |        |      0 |00:00:09.62 |   13204 |       |       |          |         |
|   2 |   OPTIMIZER STATISTICS GATHERING |          |      1 |   1096K|   1096K|00:00:07.84 |   12787 |       |       |          |         |
|   3 |    SORT ORDER BY                 |          |      1 |   1096K|   1096K|00:00:07.61 |   12787 |    81M|  3961K|   20M (1)|      67M|
|*  4 |     HASH JOIN                    |          |      1 |   1096K|   1096K|00:00:00.71 |   12787 |    19M|  3412K|   19M (0)|         |
|   5 |      TABLE ACCESS FULL           | CF10     |      1 |    500K|    500K|00:00:00.05 |    4583 |       |       |          |         |
|   6 |      TABLE ACCESS FULL           | CF11     |      1 |   1096K|   1096K|00:00:00.12 |    8204 |       |       |          |         |
-----------------------------------------------------------------------------------------------------------------------------------------
   4 - access("D"."SLE_NO"="H"."SLE_NO")

[운영 · MD 화면 · 카페모카 2023년 한 해 (6,183줄)]
---------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |      1 |        |    365 |00:00:00.01 |      81 |
|   1 |  SORT GROUP BY NOSORT         |              |      1 |    365 |    365 |00:00:00.01 |      81 |
|*  2 |   FILTER                      |              |      1 |        |   6183 |00:00:00.01 |      81 |
|   3 |    TABLE ACCESS BY INDEX ROWID| CF11_ANL     |      1 |   6200 |   6183 |00:00:00.01 |      81 |
|*  4 |     INDEX RANGE SCAN          | CF11_ANL_X01 |      1 |   6200 |   6183 |00:00:00.01 |      21 |
---------------------------------------------------------------------------------------------------------

[개발 서버 · 정리안대로 적재한 뒤 · 같은 메뉴, 같은 기간]
---------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |      1 |        |    365 |00:00:00.09 |    3689 |
|   1 |  SORT GROUP BY NOSORT         |              |      1 |    365 |    365 |00:00:00.09 |    3689 |
|*  2 |   FILTER                      |              |      1 |        |   6183 |00:00:00.09 |    3689 |
|   3 |    TABLE ACCESS BY INDEX ROWID| CF11_ANL     |      1 |   6200 |   6183 |00:00:00.09 |    3689 |
|*  4 |     INDEX RANGE SCAN          | CF11_ANL_X01 |      1 |   6200 |   6183 |00:00:00.01 |      21 |
---------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(:D_FROM<=:D_TO)
   4 - access("ITM_NO"=:ITM AND "SLE_DT">=:D_FROM AND "SLE_DT"<=:D_TO)

문제 ​

  1. 두 MD 화면 계획이 모양은 같은데 Buffers가 81과 3,689로 갈린 까닭을 CF11_ANL_X01의 CLUSTERING_FACTOR와 적재 SQL로 설명하시오.
  2. 정리안을 이 적재에도 적용할지 판단하시오. 적재의 정렬 비용(첫 계획 3번 줄)과 화면의 이득을 하루 단위 숫자로 비교하시오.
  3. 적재 SQL을 어떻게 남길지 쓰고, 03시의 TEMP 부족 위험은 정렬을 지우지 않고 무엇으로 줄일지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자