테마
한빛유통 개발팀은 지난주 화면 서버에 APM(성능 추적 도구)을 붙였다. 요청 하나가 어떤 SQL을 불렀는지 따라가려고, 데이터 접근 계층이 SQL을 보내기 직전에 요청마다 다른 추적 번호를 주석으로 앞에 붙이게 했다. 배포 다음 날부터 DB 서버(코어 4개)의 CPU 사용률이 12%에서 41%로 올랐다. 조민우가 말했다. "SQL은 한 줄도 안 바꿨어요. 바인드 변수도 그대로고요."
T_ORD: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ)T_ORD_DET: 200,000행 · 896블록 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO) · 주문당 1~3건CURSOR_SHARING = EXACT · session_cached_cursors = 50// SqlTraceInterceptor.java (지난주 배포) : SQL을 보내기 직전에 추적 번호를 주석으로 붙인다
public String beforePrepare(String sql) {
String traceId = TraceContext.current().traceId(); // 요청마다 다르다 (16자리)
return "/* trace_id=" + traceId + " */ " + sql;
}
-- 주문 상세 화면의 SQL (원래 문장 · 바꾸지 않았다)
SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_ST, o.ORD_AMT, d.ITM_ID, d.ORD_QTY, d.UNT_PRC
FROM T_ORD o, T_ORD_DET d
WHERE o.ORD_SEQ = :1
AND d.ORD_SEQ = o.ORD_SEQ
[배포 전후 같은 시간대 한 시간 · V$SYSSTAT 증가분]
배포 전 배포 후
execute count 3,602,000 3,598,400
parse count (total) 3,571,300 3,569,900
parse count (hard) 9,800 3,566,200
parse time cpu (cs) 2,100 428,500
CPU used by this session (cs) 168,400 593,600
[배포 후 V$SQL · 주문 상세 문장을 찾아본 것]
SQL_ID EXECUTIONS SQL_TEXT (앞부분)
5a1c9f0d2k7wq 1 /* trace_id=4bf92f3577b34da6 */ SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_ST, …
g83m0x2bn1v5s 1 /* trace_id=7d0e41a9c2f35b18 */ SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_ST, …
1qw7z4c9h0d2u 1 /* trace_id=e19a5b0c77d24f63 */ SELECT o.ORD_SEQ, o.ORD_DT, o.ORD_ST, …
…
[한 번 실행의 계획 (배포 전후가 같다)]
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 |00:00:00.01 | 7 |
| 1 | NESTED LOOPS | | 1 | 2 | 2 |00:00:00.01 | 7 |
| 2 | TABLE ACCESS BY INDEX ROWID | T_ORD | 1 | 1 | 1 |00:00:00.01 | 3 |
|* 3 | INDEX UNIQUE SCAN | PK_T_ORD | 1 | 1 | 1 |00:00:00.01 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD_DET | 1 | 2 | 2 |00:00:00.01 | 4 |
|* 5 | INDEX RANGE SCAN | PK_T_ORD_DET | 1 | 2 | 2 |00:00:00.01 | 3 |
------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("O"."ORD_SEQ"=:1)
5 - access("D"."ORD_SEQ"=:1)