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

주문상품 모니터에서 쪽 끝에 걸린 주문은 버거만 보이고 감자와 콜라가 사라진다

중급SELECT버거327 / 700

상황 ​

본사 메뉴팀의 「주문상품 모니터」는 전 매장의 주문상품을 최신순으로 한 쪽에 30줄씩 보여 주고 「다음」 버튼으로 넘긴다. 개발자는 쪽마다 마지막 줄의 주문일자와 주문시각(ORD_DT, ORD_HMS)을 들고 있다가 다음 쪽 SQL에 넘기는 키 기반 페이징으로 만들었다. 메뉴팀: "세트 주문 하나에 버거, 감자, 콜라가 같이 들어가는데, 쪽 끝에 걸린 주문은 버거만 보이고 나머지는 다음 쪽에도 없다. 하루치를 화면으로 넘기며 세어 보면 엑셀 내려받기보다 수백 줄이 적다."

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록(블록당 약 45행) · ORD_NO · ITEM_ID · ORD_ITEM_QTY · ORD_DT VARCHAR2(8) · ORD_HMS VARCHAR2(6)
  • 같은 주문의 상품 줄은 ORD_DT와 ORD_HMS가 모두 같다(주문당 평균 2.5줄). 매장이 200개라 같은 초에 들어온 다른 매장의 주문도 하루 수백 쌍이다.
  • 인덱스: ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)(날짜순으로 쌓여 클러스터링 팩터가 좋다). ORD_ITEM_X01은 일자별 매출 집계 배치도 쓴다.
  • 하루 주문상품은 약 3,390줄이다. 통계는 최신이다.

원본 SQL ​

sql
SELECT ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS
  FROM (SELECT ORD_NO, ITEM_ID, ORD_ITEM_QTY, ORD_DT, ORD_HMS
          FROM ORD_ITEM
         WHERE ORD_DT <= :p_dt
           AND (ORD_DT < :p_dt OR ORD_HMS < :p_hms)
         ORDER BY ORD_DT DESC, ORD_HMS DESC)
 WHERE ROWNUM <= 30

실행계획 학습용 예시 ​

xplan
[다음 쪽 · :p_dt = '20131230' · :p_hms = '184512']
-----------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |              |      1 |        |     30 |00:00:00.01 |       6 |
|*  1 |  COUNT STOPKEY                 |              |      1 |        |     30 |00:00:00.01 |       6 |
|   2 |   VIEW                         |              |      1 |     30 |     30 |00:00:00.01 |       6 |
|   3 |    TABLE ACCESS BY INDEX ROWID | ORD_ITEM     |      1 |   2472K|     30 |00:00:00.01 |       6 |
|*  4 |     INDEX RANGE SCAN DESCENDING| ORD_ITEM_X01 |      1 |     30 |     30 |00:00:00.01 |       4 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=30)
   4 - access("ORD_DT"<=:P_DT)
       filter(("ORD_DT"<:P_DT OR "ORD_HMS"<:P_HMS))

[화면 · 앞 쪽 끝과 다음 쪽 처음]
  앞 쪽 29줄      998770  콜라   20131230  184513
  앞 쪽 30줄      998771  버거   20131230  184512   ← 포스트잇 ('20131230', '184512')
  어디에도 없음   998771  감자 · 콜라   20131230  184512
  어디에도 없음   998772  버거 · 감자   20131230  184512   (다른 매장, 같은 초)
  다음 쪽 1줄     998769  버거   20131230  184508

문제 ​

  1. 쪽 끝에 걸린 주문의 다른 상품 줄과 같은 초에 들어온 다른 주문이 어디에도 나오지 않는 까닭을 정렬 키와 실행계획 4번 줄의 조건으로 설명하시오.
  2. 빠지거나 겹치는 줄이 없도록 SQL과 인덱스를 고치시오. 인덱스를 새로 하나 더 둘지 ORD_ITEM_X01을 바꿀지 정하고 그 근거도 쓰시오.
  3. 고친 뒤 정합성을 무엇으로 확인할지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자