Skip to content
튜닝 연습소트 튜닝과 페이징
SORT-029

결제 대기 주문을 오래된 것부터 정리하려고 마지막 쪽으로 가면 화면이 3초씩 멈춘다

실전SELECT한빛유통334 / 700

상황 ​

정산팀의 「결제 대기 정리」는 결제 대기(PENDING) 주문을 최신순(ORD_DT DESC, ORD_SEQ DESC)으로 한 쪽에 20건씩 보여 준다. 정산팀은 오래된 대기 건부터 처리하려고 쪽 번호 칸에 마지막 쪽 근처(3,990쪽 안팎)를 넣고 넘어가는데, 그때마다 3초 넘게 멈춘다. 정산팀은 한 쪽을 처리하면(결제 확인 뒤 COMPLETE로 바꾼다) 다음 쪽으로 넘어간다. 오과장은 ROWID로 테이블 액세스를 늦추는 안, 커버링 인덱스 안, 키 기반 페이징 안을 숫자와 부작용으로 비교한 리포트를 원한다.

테이블과 인덱스 ​

  • T_ORD_BIG: 1,000,000행 · 5,826블록 · ORD_ST PENDING 8%(80,000건) · COMPLETE 90% · CANCEL 2%
  • 인덱스 IX_ORD_BIG_ST_DT (ORD_ST, ORD_DT, ORD_SEQ): 높이 3 · 리프 약 3,800블록(한 블록에 약 263개). 같은 상태의 주문은 테이블 곳곳에 흩어져 있다(클러스터링 팩터가 행 수에 가깝다).
  • 화면 칸은 ORD_SEQ, ORD_DT, CUS_ID, ORD_AMT 넷이다. 정산팀은 하루 수백 건을 PENDING에서 COMPLETE로 바꾼다.
  • 오래된 블록은 대부분 버퍼 캐시에 없다. 통계는 최신이다.

원본 SQL ​

sql
SELECT ORD_SEQ, ORD_DT, CUS_ID, ORD_AMT
  FROM (SELECT ROWNUM rn, a.*
          FROM (SELECT ORD_SEQ, ORD_DT, CUS_ID, ORD_AMT
                  FROM T_ORD_BIG
                 WHERE ORD_ST = 'PENDING'
                 ORDER BY ORD_DT DESC, ORD_SEQ DESC) a
         WHERE ROWNUM <= :page * 20)
 WHERE rn > (:page - 1) * 20

실행계획 학습용 예시 ​

xplan
[3,990쪽 · 79,781 ~ 79,800번째]   (1쪽은 같은 모양 · A-Rows 20 · Buffers 23)
----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name             | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |                  |      1 |        |     20 |00:00:03.21 |   80107 |  5512 |
|*  1 |  VIEW                           |                  |      1 |     20 |     20 |00:00:03.21 |   80107 |  5512 |
|*  2 |   COUNT STOPKEY                 |                  |      1 |        |  79800 |00:00:03.20 |   80107 |  5512 |
|   3 |    VIEW                         |                  |      1 |  80000 |  79800 |00:00:03.17 |   80107 |  5512 |
|   4 |     TABLE ACCESS BY INDEX ROWID | T_ORD_BIG        |      1 |  80000 |  79800 |00:00:03.14 |   80107 |  5512 |
|*  5 |      INDEX RANGE SCAN DESCENDING| IX_ORD_BIG_ST_DT |      1 |  80000 |  79800 |00:00:00.05 |     307 |     0 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("RN">(:PAGE-1)*20)
   2 - filter(ROWNUM<=:PAGE*20)
   5 - access("ORD_ST"='PENDING')

문제 ​

  1. 3,990쪽의 Buffers 80,107이 어디서 나오는지 실행계획으로 설명하시오.
  2. ROWID로 테이블 액세스를 늦추는 안, 커버링 인덱스 안, 키 기반 페이징 안을 각각 SQL(또는 DDL)로 쓰고, 1쪽과 3,990쪽의 예상 일량과 부작용을 비교하시오.
  3. 정산팀이 마지막 쪽으로 가는 까닭을 생각해 하나를 권하시오. 정산팀이 처리한 건이 목록에서 빠질 때 쪽 번호 페이징과 키 기반 페이징에 각각 무슨 일이 생기는지도 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자