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

2페이지에 1페이지 끝 주문이 또 나오고, 어떤 주문은 어디에도 없다

실전SELECT버거310 / 700

상황 ​

매장 점장용 「우리 매장 주문 목록」은 최신순으로 한 페이지에 20건씩 보여 준다. SH0017 점장: "2페이지 맨 위가 1페이지 끝에서 본 주문이다. 엑셀로 내려받은 목록에 있는 주문이 화면을 끝까지 넘겨도 안 나온다. 그리고 넘길 때마다 0.3초씩 걸린다." 화면 요구서에는 "주문일 최신순" 한 줄뿐이어서 SQL도 ORDER BY ORD_DT DESC 하나다. 200개 매장 점장이 마감 무렵에 몰아서 연다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) 날짜만('20131229') · ORD_HMS VARCHAR2(6) · SHOP_NO 200개 매장 · ORD_NO NUMBER(PK)
  • 매장 SH0017의 주문은 5,012건이다. 하루 약 7건이라 같은 ORD_DT가 7줄씩 있다.
  • 인덱스는 ORD_PK (ORD_NO)와 ORD_X01 (ORD_DT, ORD_HMS)이고, SHOP_NO로 시작하는 인덱스는 없다.
  • 화면에 보이는 칸은 ORD_NO, ORD_DT, ORD_HMS 셋이다. 통계는 최신이다.

원본 SQL ​

sql
SELECT ORD_NO, ORD_DT, ORD_HMS
  FROM (SELECT ROWNUM AS rn, a.*
          FROM (SELECT ORD_NO, ORD_DT, ORD_HMS
                  FROM ORD
                 WHERE SHOP_NO = :shop
                 ORDER BY ORD_DT DESC) a
         WHERE ROWNUM <= :page * 20)
 WHERE rn > (:page - 1) * 20

실행계획 학습용 예시 ​

xplan
[2페이지 — :shop = 'SH0017' · :page = 2]
---------------------------------------------------------------------------------------------------------
| Id  | Operation                 | Name | Starts | E-Rows | A-Rows |    A-Time   | Buffers |  Used-Mem |
---------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |      |      1 |        |     20 | 00:00:00.31 |   22422 |           |
|*  1 |  VIEW                     |      |      1 |     40 |     20 | 00:00:00.31 |   22422 |           |
|*  2 |   COUNT STOPKEY           |      |      1 |        |     40 | 00:00:00.31 |   22422 |           |
|   3 |    VIEW                   |      |      1 |   5000 |     40 | 00:00:00.31 |   22422 |           |
|*  4 |     SORT ORDER BY STOPKEY |      |      1 |   5000 |     40 | 00:00:00.31 |   22422 | 4096  (0) |
|*  5 |      TABLE ACCESS FULL    | ORD  |      1 |   5000 |   5012 | 00:00:00.30 |   22422 |           |
---------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("RN">(:PAGE-1)*20)
   2 - filter(ROWNUM<=:PAGE*20)
   4 - filter(ROWNUM<=:PAGE*20)
   5 - filter("SHOP_NO"=:SHOP)

[화면 — 경계에 걸린 날 20131229 · SH0017 의 그날 주문 7 건]
  1페이지 15 ~ 20번   995702 · 995431 · 995288 · 994612 · 995103 · 994780
  2페이지 21번        995103                       ← 1페이지 19번과 같은 주문
  어느 페이지에도 없음 994955

문제 ​

  1. 같은 주문이 두 페이지에 나오고 어떤 주문은 어디에도 없는 까닭을 정렬 키와 실행계획 4번 줄로 설명하시오.
  2. 정합성(빠지거나 겹치는 주문이 없음)과 성능(어느 페이지든 비슷한 일량)을 함께 고친 SQL과 인덱스를 작성하시오.
  3. 'n 페이지 바로 가기'를 지키는 안과 '다음 페이지'만 두는 안을 비교하고, 각 안의 대가(부작용)와 정합성 확인 방법을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자