테마
고객센터 「최근 완료 주문」 화면은 고객 번호를 받아 완료된 주문을 최신순으로 20건 보여 준다. 상담원 40명이 시간당 1,900번쯤 연다. 목요일 아침부터 화면이 굼뜨다는 말이 나왔다. DBA의 첫 답은 이랬다. "AWR에서 PLAN_HASH_VALUE가 수요일과 같습니다. DISPLAY_AWR로 펼쳐 봐도 계획이 똑같아요. 계획 문제는 아니고 서버 쪽을 봐야겠습니다." 목요일 05:30에는 고객센터 WAS 패치가 있었다(JDBC 드라이버 교체, 연결 설정 파일도 업체 기본값으로 바뀜). DB 쪽 변경은 없었다.
T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_ST COMPLETE 90% · 고객 2,000명(고객마다 상태가 하나 · COMPLETE 고객 1,800명은 각 500건) · CUS_ID VARCHAR2(40)IX_ORD_BIG_ST_CUS_DT (ORD_ST, CUS_ID, ORD_DT): BLEVEL 2 · 리프 3,330블록(COMPLETE 부분 약 3,000블록)-- 「최근 완료 주문」 (SQL_ID 0v7c2nq8m4k1x)
SELECT ORD_SEQ, ORD_DT, ORD_AMT
FROM T_ORD_BIG
WHERE ORD_ST = 'COMPLETE'
AND CUS_ID = :cus_id
ORDER BY ORD_DT DESC
FETCH FIRST 20 ROWS ONLY
[DBA_HIST_SQLSTAT · SQL_ID 0v7c2nq8m4k1x]
SNAP_ID 시작 PLAN_HASH_VALUE EXECUTIONS_DELTA BUFFER_GETS_DELTA 실행당 블록
5210 수 10:00 2786091352 1,820 41,860 23
5211 수 11:00 2786091352 1,905 43,815 23
5230 목 10:00 2786091352 1,884 2,865,564 1,521
5231 목 11:00 2786091352 1,913 2,909,673 1,521
[DBMS_XPLAN.DISPLAY_AWR('0v7c2nq8m4k1x') · 계획 하나 · AWR에는 조건절이 남지 않는다]
VIEW → WINDOW NOSORT STOPKEY → TABLE ACCESS BY INDEX ROWID T_ORD_BIG → INDEX RANGE SCAN DESCENDING IX_ORD_BIG_ST_CUS_DT
[V$SQL · 지금] 자식 0(LAST_ACTIVE 수 23:58) · 자식 1(목 06:12부터) · 둘 다 PLAN_HASH_VALUE 2786091352
[V$SQL_SHARED_CURSOR · 자식 1] BIND_MISMATCH = Y
[V$SQL_BIND_CAPTURE] 자식 0 :CUS_ID VARCHAR2(128) · 자식 1 :CUS_ID NVARCHAR2(128)
[자식 0 · 수요일 · :cus_id = 'CUS_001207']
---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.01 | 23 |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.01 | 23 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 500 | 20 |00:00:00.01 | 23 |
| 3 | TABLE ACCESS BY INDEX ROWID | T_ORD_BIG | 1 | 500 | 20 |00:00:00.01 | 23 |
|* 4 | INDEX RANGE SCAN DESCENDING| IX_ORD_BIG_ST_CUS_DT | 1 | 500 | 20 |00:00:00.01 | 3 |
---------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=20)
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("ORD_DT") DESC )<=20)
4 - access("ORD_ST"='COMPLETE' AND "CUS_ID"=:CUS_ID)
[자식 1 · 목요일 · 같은 고객]
---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:00.03 | 1212 |
|* 1 | VIEW | | 1 | 20 | 20 |00:00:00.03 | 1212 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 9000 | 20 |00:00:00.03 | 1212 |
| 3 | TABLE ACCESS BY INDEX ROWID | T_ORD_BIG | 1 | 9000 | 20 |00:00:00.03 | 1212 |
|* 4 | INDEX RANGE SCAN DESCENDING| IX_ORD_BIG_ST_CUS_DT | 1 | 9000 | 20 |00:00:00.03 | 1192 |
---------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=20)
2 - filter(ROW_NUMBER() OVER ( ORDER BY INTERNAL_FUNCTION("ORD_DT") DESC )<=20)
4 - access("ORD_ST"='COMPLETE')
filter(SYS_OP_C2C("CUS_ID")=:CUS_ID)