테마
고객센터 「최근 주문 5건」 칸은 고객 번호를 넣으면 그 고객의 최근 주문 다섯 건을 보여 준다. 상담원들이 하루 1만 번쯤 연다. 2016년에 만든 SQL에는 ORDER BY가 없고, INDEX_DESC 힌트와 ROWNUM으로 최근 5건을 뽑는다. 주석은 "정렬 없이 인덱스 역순으로 최근 5건 (2016 강도현)"이다.
지난달 운영 DB를 11g에서 19c로 올린 뒤, 상담원 신고가 열두 건 들어왔다. "가끔 5월 주문이 6월 주문보다 위에 나오고, 어떤 때는 어제 주문이 빠져 있다." 다시 열면 멀쩡하고, 주로 아침 첫 조회에서 생긴다. 실행계획은 한 줄만 바뀌었다.
T_ORD: 100,000행 · 896블록(블록당 약 112행) · ORD_SEQ 순으로 쌓였다 · ORD_DT DATE(시분초 있음) · 고객당 50건, 한 고객의 주문은 ORD_SEQ 2,000건 간격이라 50건이 50블록에 흩어져 있다IX_T_ORD_CUS_DT (CUS_ID, ORD_DT): BLEVEL 1 · 리프 약 375블록 · CLUSTERING_FACTOR 약 100,000 · 통계 최신SELECT /*+ INDEX_DESC(o IX_T_ORD_CUS_DT) */
o.ORD_SEQ, o.ORD_DT, o.ORD_ST, o.ORD_AMT
FROM T_ORD o
WHERE o.CUS_ID = :v_cus
AND ROWNUM <= 5
[업그레이드 전 11g: 보관해 둔 계획]
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 |00:00:00.01 | 7 |
|* 1 | COUNT STOPKEY | | 1 | | 5 |00:00:00.01 | 7 |
| 2 | TABLE ACCESS BY INDEX ROWID | T_ORD | 1 | 5 | 5 |00:00:00.01 | 7 |
|* 3 | INDEX RANGE SCAN DESCENDING | IX_T_ORD_CUS_DT | 1 | 50 | 5 |00:00:00.01 | 2 |
---------------------------------------------------------------------------------------------------------------------
[지금 19c]
---------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 5 |00:00:00.01 | 7 |
|* 1 | COUNT STOPKEY | | 1 | | 5 |00:00:00.01 | 7 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD | 1 | 5 | 5 |00:00:00.01 | 7 |
|* 3 | INDEX RANGE SCAN DESCENDING | IX_T_ORD_CUS_DT | 1 | 50 | 5 |00:00:00.01 | 2 |
---------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=5)
3 - access("O"."CUS_ID"=:V_CUS)