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

타임세일이 시작되면 결제 완료 콜백이 3초를 넘겨 결제 대행사가 같은 콜백을 다시 보낸다

중급UPDATE한빛유통558 / 700

상황 ​

한빛유통 쇼핑몰은 결제 대행사(PG)가 결제 완료를 알려 오면(콜백) 주문의 상태와 결제 정보를 고친다. 평소에는 초당 몇 건이지만, 저녁 8시 타임세일이 시작되면 처음 10분 동안 초당 140건까지 몰린다. PG는 3초 안에 응답이 없으면 같은 콜백을 다시 보낸다. 지난 금요일 20:00 ~ 20:10에 들어온 재시도 콜백만 11,400건이었다.

테이블과 인덱스 ​

  • T_ORD: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · ORD_ST(PENDING → COMPLETE) · PAY_TP(CARD, BANK, POINT) · PAY_DT · PAY_AMT
  • 콜백 API 서버 8대가 스레드 16개씩 DB에 붙는다.
  • CURSOR_SHARING = EXACT

원본 SQL ​

sql
// PgCallbackController.java : 콜백 값을 문자열로 이어 붙여 UPDATE 한다
String sql = "UPDATE T_ORD SET ORD_ST = 'COMPLETE', PAY_DT = SYSDATE, PAY_TP = '" + payTp
           + "', PAY_AMT = " + payAmt + " WHERE ORD_SEQ = " + ordSeq;
try (Statement st = conn.createStatement()) {
    st.executeUpdate(sql);
}
conn.commit();

실행계획 학습용 예시 ​

xplan
[ASH · 금요일 20:00 ~ 20:10 · 콜백 세션의 표본 비율]
  CPU                               38%
  latch: shared pool                26%
  library cache: mutex X            11%
  enq: TX - row lock contention      9%    (재시도 콜백이 아직 처리 중인 같은 주문을 고치려고 기다린다)
  row cache mutex                    6%

[V$SYSSTAT · 20:00 ~ 20:10 증가분]
  execute count                  97,100
  parse count (hard)             95,860
  parse time cpu                 61,400 cs
  CPU used by this session       84,900 cs

[V$SQLAREA · 20:10 · FORCE_MATCHING_SIGNATURE로 묶은 맨 위 무리]
  PARENTS   EXECS     MB   SAMPLE
    6,210   6,480   98.4   UPDATE T_ORD SET ORD_ST = 'COMPLETE', PAY_DT = SYSDATE, PAY_TP = 'CARD', PAY_AMT = 38500 WHERE ORD_SEQ = 98431

[콜백 응답 시간]  평소 p99 0.04초 · 20:00 ~ 20:10 p99 2.9초 · 3초 넘김 11,400건 (모두 재시도로 돌아왔다)

[한 번 실행의 계획]
-------------------------------------------------------------------------------------------
| Id  | Operation          | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |          |      1 |        |      0 |00:00:00.01 |       4 |
|   1 |  UPDATE            | T_ORD    |      1 |        |      0 |00:00:00.01 |       4 |
|*  2 |   INDEX UNIQUE SCAN| PK_T_ORD |      1 |      1 |      1 |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ORD_SEQ"=98431)

문제 ​

  1. 행 하나를 고치는 UPDATE가 3초를 넘기는 이유를 위 자료로 설명하시오. 재시도 콜백이 상황을 어떻게 키우는지도 쓰시오.
  2. 콜백 처리 SQL을 고치시오. 문장 안의 상수 가운데 바인드 변수로 바꿀 것과 그대로 둬도 되는 것을 가려 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자