테마
한빛유통이 지난달 내놓은 모바일 앱의 「내 등급」 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' 모양이다.CURSOR_SHARING = EXACT// 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)) { /* 한 건 */ }
[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')
LOADS와 이웃 문장의 숫자로 평가하시오.