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

월 마감 업로드가 도는 3분 동안 매장 POS의 메뉴 화면까지 굼떠진다

기초INSERT버거549 / 700

상황 ​

버거 본사는 매달 1일 새벽에 매장 PC에 쌓인 지난달 주문상품을 받아 ORD_ITEM에 넣는다. 수신 프로그램(2013년, C#)은 한 줄을 읽을 때마다 INSERT 문자열을 새로 만들어 보낸다. 2013년 12월분 103,030행을 넣는 데 3분 34초가 걸렸다. 같은 시각, 밤새 문을 여는 매장들에서 "메뉴 화면이 한 박자씩 늦게 뜬다"는 연락이 왔다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS) · 한 달 약 103,000행
  • ORD_NO와 ITEM_ID는 NUMBER이고, ORD_DT('20131201')와 ORD_HMS('113005')는 VARCHAR2다.
  • 매장 POS의 조회 문장(메뉴 가격, 매장 정보)은 바인드 변수로 쓰여 있고, 평소에는 공유 풀에 늘 올라와 있다.
  • CURSOR_SHARING = EXACT · session_cached_cursors = 50

원본 SQL ​

sql
// MonthUpload.cs (2013) : 한 줄마다 값을 문자열에 이어 붙여 INSERT 문장을 새로 만든다
using (var tx = conn.BeginTransaction())
{
    var cmd = conn.CreateCommand();
    foreach (var r in rows)                        // 2013년 12월분 103,030행
    {
        cmd.CommandText = "INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS) VALUES ("
                        + r.OrdNo + ", " + r.ItemId + ", " + r.Qty + ", '" + r.OrdDt + "', '" + r.OrdHms + "')";
        cmd.ExecuteNonQuery();
    }
    tx.Commit();
}

-- DB에 도착하는 문장 (행마다 하나)
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS) VALUES (998201, 17, 2, '20131201', '113005')

실행계획 학습용 예시 · 파싱 비율은 교재 11화 실측과 같은 수준 ​

xplan
[세션 통계 — 2013년 12월분 업로드 한 번 (V$MYSTAT 증가분)]
  경과 시간                          214 초
  execute count                      103,046
  parse count (total)                103,051
  parse count (hard)                 103,012
  parse time cpu                      12,360 cs
  CPU used by this session            15,840 cs
  session logical reads              721,400   (행당 약 7 : INSERT 5 + 하드 파싱의 딕셔너리 조회 2)
  SQL*Net roundtrips to/from client  103,070

[10046 → TKPROF — 표가 103,012개다. 그중 둘]
INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS) VALUES (998201, 17, 2, '20131201', '113005')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          1          4           1
Misses in library cache during parse: 1

INSERT INTO ORD_ITEM (ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS) VALUES (998201, 42, 1, '20131201', '113005')

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          1          4           1
Misses in library cache during parse: 1

[업로드 전후 · POS 문장의 V$SQLAREA]
  문장                         LOADS (업로드 전 → 후)   INVALIDATIONS
  메뉴 가격 조회 (바인드)         1 → 6                    0
  매장 정보 조회 (바인드)         1 → 4                    0

문제 ​

  1. 행당 7블록을 읽는 INSERT가 3분 넘게 걸리는 이유를 세션 통계와 TKPROF로 설명하시오. 업로드하는 동안 POS 화면까지 느려진 이유도 쓰시오.
  2. 같은 결과를 내도록 업로드 프로그램을 고치시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자