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

모바일 「내 등급」 API를 연 뒤로 정산 목록 커서가 하루에도 몇 번씩 다시 파싱된다

중급SELECT한빛유통553 / 700

상황 ​

한빛유통이 지난달 내놓은 모바일 앱의 「내 등급」 API는 고객 번호로 고객 한 명을 읽는다. 고객 2,000명이 하루 평균 열두 번쯤 앱을 열어 하루 약 24,000번 호출된다. 리뷰에서 바인드 변수를 쓰라고 하자 개발 리더가 답했다. "고객이 2,000명이니 문장도 많아야 2,000개입니다. 한 번씩만 하드 파싱하면 그다음부터는 공유됩니다." 그 뒤로 DBA는 정산 목록(Q4) 같은 이웃 커서가 하루에도 몇 번씩 다시 하드 파싱된다고 알려 왔다.

테이블과 인덱스 ​

  • M_CUS: 2,000행 · 30블록 · PK_M_CUS (CUS_ID) · CUS_ID는 'CUS_000123' 모양이다.
  • 회원 가입이 열려 있어서 고객은 계속 는다.
  • 공유 풀에는 화면과 배치의 바인드 문장 약 900개가 늘 올라와 있다. 그중 정산 목록(Q4)과 월 매출(Q1)은 하루 수만 번 실행된다.
  • CURSOR_SHARING = EXACT

원본 SQL ​

sql
// GradeApi.java : 고객 번호를 문자열로 이어 붙인다
String sql = "SELECT CUS_NM, CUS_GD, RGN_ID FROM M_CUS WHERE CUS_ID = '" + cusId + "'";
try (Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql)) { /* 한 건 */ }

실행계획 학습용 예시 ​

xplan
[V$SQLAREA · 18:00 · FORCE_MATCHING_SIGNATURE로 묶은 이 API 무리]
  PARENTS    EXECS    LOADS     MB    SAMPLE
    1,286   15,410    3,377   20.6    SELECT CUS_NM, CUS_GD, RGN_ID FROM M_CUS WHERE CUS_ID = 'CUS_000123'

[같은 시각 · 이웃 문장 (API를 내놓기 전 주에는 하루 내내 LOADS 1이었다)]
  문장                       LOADS   INVALIDATIONS
  Q4 정산 목록 다음 페이지       6               0
  Q1 월 매출                     4               0

[V$SYSSTAT · 09:00 ~ 18:00 증가분]
  parse count (hard)          4,860    (API를 내놓기 전 주 같은 시간대 412)

[한 번 실행의 계획]
------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |      1 |        |      1 |00:00:00.01 |       2 |
|   1 |  TABLE ACCESS BY INDEX ROWID| M_CUS    |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  2 |   INDEX UNIQUE SCAN         | PK_M_CUS |      1 |      1 |      1 |00:00:00.01 |       1 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("CUS_ID"='CUS_000123')

문제 ​

  1. 개발 리더의 말(한 번씩만 하드 파싱하면 그다음부터는 공유된다)이 맞는지 LOADS와 이웃 문장의 숫자로 평가하시오.
  2. SQL을 고치고, 이 문장을 바인드 변수로 바꿔도 값에 따라 실행계획이 달라질 걱정이 없는 이유를 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자