테마
본사 「일별 판매 건수 추이」 화면은 시작일과 종료일을 골라 날짜마다 판매 건수를 그래프로 보여 준다(하루 2,000번쯤, 기간은 하루 ~ 2년). 지난달 인스턴스의 CURSOR_SHARING = FORCE를 EXACT로 되돌린 뒤로 이 화면이 하드 파싱 상위에 올라왔다.
리뷰에서 바인드 변수를 쓰라고 하자 개발자가 답했다. "바인드로 바꾸면 처음 들어온 값이 계획을 정한다고 들었습니다. 기간이 하루일 때와 2년일 때 계획이 같을 리 없잖아요."
CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) '20230601' · 하루 약 706건 · 약 2년치IX_CF10_SLE_DT (SLE_DT): 리프 1,393블록 · 통계 최신 · 히스토그램 없음CURSOR_SHARING = EXACT · 바인드 피킹 켬// SalesTrendDao.java : 날짜를 SQL 문자열에 이어 붙인다 (화면이 'YYYYMMDD'를 넘긴다)
String sql = "SELECT SLE_DT, COUNT(*) AS SLE_CNT FROM CF10 "
+ "WHERE SLE_DT BETWEEN '" + from + "' AND '" + to + "' "
+ "GROUP BY SLE_DT ORDER BY SLE_DT";
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
[같은 모양의 문장을 기간별로 (리터럴 · 실측)]
기간 A-Rows 계획 Buffers
하루 706 INDEX RANGE SCAN IX_CF10_SLE_DT + SORT GROUP BY NOSORT 4
31일 21,890 〃 63
1년 257,700 〃 720
2년 전체 500,000 〃 (INDEX FAST FULL SCAN + HASH GROUP BY도 비슷) 1,395
(테이블에는 어느 기간이든 가지 않는다 · FULL이면 4,583)
[V$SQLAREA — 어제 하루 · FORCE_MATCHING_SIGNATURE 하나로 묶은 무리]
PARENTS 1,310 · EXECS 2,140 · 하드 파싱 1,310 · SHARABLE_MEM 24.1MB
[31일 한 번]
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 31 |00:00:00.01 | 63 |
| 1 | SORT GROUP BY NOSORT | | 1 | 31 | 31 |00:00:00.01 | 63 |
|* 2 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 21886 | 21890 |00:00:00.01 | 63 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SLE_DT">='20230601' AND "SLE_DT"<='20230701')