Skip to content
튜닝 연습파싱과 바인드 변수
PARSE-039

정보계를 클라우드로 옮긴 뒤 월별 매장 주문 리포트 적재가 2초에서 53초가 됐다

실전INSERT버거584 / 700

상황 ​

버거 본사 정보계 DB(RPT)는 POS 운영 DB를 DB 링크 @POS로 읽는다. 매달 초 「매장별 월 주문 건수」를 정보계 테이블 RPT_SHOP_MON에 적재한다(2013년이면 매장 200곳 × 12개월 = 2,400행). 지난달 정보계를 클라우드로 옮긴 뒤 이 적재가 2.2초에서 53초가 됐다. SQL은 한 글자도 바뀌지 않았다. 인프라팀은 "전용선 대역폭을 두 배로 늘리겠다"라고 하고, 선배는 DRIVING_SITE 힌트 한 줄이면 된다고 한다. 박팀장은 대안을 비교해 하나를 고르고 무엇을 잃는지도 적어 달라고 했다.

테이블과 인덱스 ​

  • (POS 운영 DB) ORD 주문: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · SHOP_NO VARCHAR2(6) · 2013년 약 50만 건 · 인덱스 ORD_X02 (SHOP_NO, ORD_DT, ORD_HMS, ORD_NO)(이 문제에서는 있다, 리프 약 5,000블록)
  • (정보계) SHOP_AREA 매장 권역: 200행 · 5블록 · SHOP_NO · AREA_CD(날마다 SHOP을 복제하며 권역을 붙인 표)
  • (정보계) RPT_MONTH 월 달력: 12행 · 4블록 · YM('201301' ~ '201312') · FROM_DT(그달 1일) · TO_DT(그달 말일)
  • (정보계) RPT_SHOP_MON 적재 대상: YM · SHOP_NO · AREA_CD · ORD_CNT · 인덱스 없음
  • 정보계와 POS 운영 DB 사이의 왕복은 옮기기 전 0.4ms, 지금 11ms다. 운영 DB는 낮에 POS 결제를 받는다.

원본 SQL ​

sql
-- 매달 초 적재 (2016) : 매장 × 월마다 운영 DB에 건수를 묻는다
INSERT INTO RPT_SHOP_MON (YM, SHOP_NO, AREA_CD, ORD_CNT)
SELECT m.YM, s.SHOP_NO, s.AREA_CD,
       (SELECT COUNT(*)
          FROM ORD@POS o
         WHERE o.SHOP_NO = s.SHOP_NO
           AND o.ORD_DT BETWEEN m.FROM_DT AND m.TO_DT) AS ORD_CNT
  FROM RPT_MONTH m, SHOP_AREA s
 WHERE m.YM BETWEEN '201301' AND '201312';

실행계획 학습용 예시 ​

xplan
[정보계 · DISPLAY_CURSOR · 적재 한 번]
------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Inst   |IN-OUT|
------------------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT          |              |      1 |        |      0 |00:00:53.10 |    2523 |        |      |
|   1 |  LOAD TABLE CONVENTIONAL  | RPT_SHOP_MON |      1 |        |      0 |00:00:53.10 |    2523 |        |      |
|   2 |   REMOTE                  | ORD          |   2400 |      1 |   2400 |00:00:52.71 |       0 |    POS | R->S |
|   3 |   MERGE JOIN CARTESIAN    |              |      1 |   2400 |   2400 |00:00:00.01 |       9 |        |      |
|*  4 |    TABLE ACCESS FULL      | RPT_MONTH    |      1 |     12 |     12 |00:00:00.01 |       4 |        |      |
|   5 |    BUFFER SORT            |              |     12 |    200 |   2400 |00:00:00.01 |       5 |        |      |
|   6 |     TABLE ACCESS FULL     | SHOP_AREA    |      1 |    200 |    200 |00:00:00.01 |       5 |        |      |
------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - filter(("M"."YM">='201301' AND "M"."YM"<='201312'))

Remote SQL Information (identified by operation id):
----------------------------------------------------
   2 - SELECT COUNT(*) FROM "ORD" "O" WHERE "O"."SHOP_NO"=:1 AND "O"."ORD_DT">=:2 AND "O"."ORD_DT"<=:3 (accessing 'POS' )

[정보계 세션 · V$SESSION_EVENT]
  SQL*Net message from dblink       4,801번 · 52.3 초 (평균 10.9 ms)
  SQL*Net message to dblink         4,801번 ·  0.02 초

[POS 운영 DB · 원격 문장의 V$SQL]
  SELECT COUNT(*) FROM "ORD" "O" WHERE ...   EXECUTIONS 2,400 · BUFFER_GETS 7,212 · ELAPSED 0.21 초 · INDEX RANGE SCAN (ORD_X02)

[옮기기 전 같은 적재]  2.2 초 · message from dblink 4,801번 · 1.9 초

문제 ​

  1. 적재가 2.2초에서 53초가 된 이유를 계획의 Starts와 대기 통계로 설명하시오. 대역폭 증설안을 평가하시오.
  2. 결과가 바뀌지 않게 적재를 고치시오. 선배의 DRIVING_SITE 안이 이 문장에서 통하는지도 쓰시오.
  3. 고른 안과 다른 안(대역폭 증설, DRIVING_SITE, 운영 DB 쪽 요약 복제)을 견주어 각각 무엇을 잃는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자