Skip to content
튜닝 연습PL/SQL과 사용자 정의 함수
PLSQL-026

10분마다 도는 택배 상태 반영이 AWR의 실행 횟수 1위와 2위를 차지한다

중급PLSQL한빛유통676 / 700

상황 ​

한빛유통은 택배사 다섯 곳이 보내는 배송 상태 파일을 10분마다 받아 주문별 배송 추적 테이블에 반영한다. 고객센터 화면과 주문 조회 화면이 이 테이블을 읽는다. DBA가 주간 AWR을 보다가 「SQL ordered by Executions」의 1위와 2위가 이 프로그램의 UPDATE와 INSERT인 것을 찾았다. 그 시간대에는 주문 화면과 CPU를 나눠 쓴다. 개발자는 이렇게 말한다. "FORALL로 묶으면 어느 주문이 UPDATE 0건이었는지 알 수 없어서 루프로 뒀어요."

테이블과 인덱스 ​

  • T_DLV_RCV(택배사 수신, 이 문제용): RCV_NO(회차) · ORD_SEQ · DLV_CO · RAW_ST · EVT_DT · 회차마다 평균 4,400행 · 인덱스 IX_DLV_RCV_NO (RCV_NO)
  • 수신 프로그램이 주문마다 최신 상태 한 행만 남기므로, 한 회차에 같은 주문은 한 번만 온다.
  • T_DLV_TRACK(배송 추적, 이 문제용): 주문당 한 행 · PK_T_DLV_TRACK (ORD_SEQ) · DLV_CO · DLV_ST · LAST_EVT_DT
  • 한 회차 4,400행 가운데 약 4,050행은 이미 추적 중인 주문(UPDATE)이고, 약 350행은 처음 오는 주문(INSERT)이다.
  • PKG_DLV_MAP.TO_STD(dlv_co, raw_st): 택배사별 상태 코드를 표준 코드로 바꾸는 PL/SQL 함수(SQL 없음) · 고객센터 화면도 같은 함수를 쓴다
  • 회차는 06:00 ~ 24:00에 10분마다, 하루 108번 돈다.

원본 SQL ​

sql
PROCEDURE APPLY_DLV_STATUS(p_rcv_no NUMBER) IS
  v_st VARCHAR2(10);
BEGIN
  FOR r IN (SELECT ORD_SEQ, DLV_CO, RAW_ST, EVT_DT
              FROM T_DLV_RCV
             WHERE RCV_NO = p_rcv_no) LOOP
    v_st := PKG_DLV_MAP.TO_STD(r.DLV_CO, r.RAW_ST);
    UPDATE T_DLV_TRACK
       SET DLV_ST = v_st, LAST_EVT_DT = r.EVT_DT
     WHERE ORD_SEQ = r.ORD_SEQ;
    IF SQL%ROWCOUNT = 0 THEN                     -- 처음 오는 주문
      INSERT INTO T_DLV_TRACK (ORD_SEQ, DLV_CO, DLV_ST, LAST_EVT_DT)
      VALUES (r.ORD_SEQ, r.DLV_CO, v_st, r.EVT_DT);
    END IF;
  END LOOP;
  COMMIT;
END;

실행계획 학습용 예시 ​

xplan
[AWR — 하루치 (SQL ordered by Executions)]
   Executions   Rows Processed   CPU (s)   SQL
      475,236          437,412      31.2   UPDATE T_DLV_TRACK SET DLV_ST = :B3 , LAST_EVT_DT = :B2 WHERE ORD_SEQ = :B1
       37,824           37,824       4.9   INSERT INTO T_DLV_TRACK (ORD_SEQ, DLV_CO, DLV_ST, LAST_EVT_DT) VALUES (:B4 , …)
          108          475,236       0.4   SELECT ORD_SEQ, DLV_CO, RAW_ST, EVT_DT FROM T_DLV_RCV WHERE RCV_NO = :B1

[한 회차 — 4,400행 (V$MYSTAT 증가분)]
  경과 0.41 초 · CPU 0.38 초 · recursive calls 4,797 · execute count 4,752
  session logical reads 20,614 · redo size 2.0 MB

문제 ​

  1. 한 회차에 SQL이 몇 번 실행되는지 AWR과 세션 통계로 설명하시오.
  2. 결과가 바뀌지 않게 반영 프로그램을 고치시오. FORALL에서 원소마다 UPDATE된 행 수를 어떻게 아는지도 쓰시오.
  3. 고친 프로그램이 원래 프로그램과 같은 결과를 내기 위한 전제 조건을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자