Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-025

DB를 19c로 올린 뒤 고객센터의 「최근 주문 5건」이 가끔 날짜 순서가 뒤섞여 나온다

중급SELECT한빛유통100 / 700

상황 ​

고객센터 「최근 주문 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 · 통계 최신

원본 SQL ​

sql
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

실행계획 학습용 예시 · 건수는 적재 스크립트 그대로 ​

xplan
[업그레이드 전 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)

문제 ​

  1. 업그레이드 전후 계획에서 달라진 줄을 짚고, 그 변화 때문에 이 SQL이 '최근 5건'과 그 순서를 보장하지 못하게 된 이유를 설명하시오. Buffers가 7로 같은 이유도 설명하시오.
  2. 늘 최근 5건이 날짜 역순으로 나오도록 SQL을 고치시오. 고친 SQL이 정렬 없이 5건에서 멈추는지 확인하는 방법과, 멈추지 않을 때 어떻게 할지도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자