Skip to content
튜닝 연습서브쿼리와 쿼리 변환
SUBQ-052

점주 앱의 「주간 주문 추이」가 매장 한 곳의 일주일을 보는데 주문 2년 치를 읽는다

중급SELECT버거287 / 700

상황 ​

가맹점주 앱의 「주간 주문 추이」는 매장 한 곳의 일주일치 일별 주문 수와 전일 대비 증감을 보여 준다. 점주 200명이 아침마다 열어서 출근 시간에 0.3초짜리 호출이 몰린다. 화면 SQL은 공통 뷰 V_SHOP_DAY에 매장과 기간 조건을 건다. 조민우는 "매장 조건은 뷰 안으로 들어가는데 날짜 조건은 왜 안 들어가는지 모르겠다. 날짜 조건을 뷰 안에 직접 넣어 보니 빨라지긴 했는데 첫날 증감이 비어 나온다"라고 한다.

테이블과 인덱스 ​

  • ORD 주문: 1,000,000행 · 22,422블록 · ORD_DT VARCHAR2(8) · 2012 ~ 2013년 730일 · 날짜순 적재 · 하루치 약 1,370건이 31블록에 모여 있다
  • 인덱스 ORD_X01 (ORD_DT, ORD_HMS) · 하루치 리프 약 5블록 · SHOP_NO에는 인덱스가 없다
  • 매장 200곳 · 모든 매장이 2년 동안 하루도 빠짐없이 주문을 받았다(한 매장 하루 약 7건) · 통계 최신
  • 아래 실행계획은 :shop = 'SH0042', :d1 = '20130311', :d2 = '20130317'

원본 SQL ​

sql
-- 공통 뷰: 매장 일별 주문 수와 전일 주문 수
CREATE OR REPLACE VIEW V_SHOP_DAY AS
SELECT SHOP_NO, ORD_DT, COUNT(*) AS ORD_CNT,
       LAG(COUNT(*)) OVER (PARTITION BY SHOP_NO ORDER BY ORD_DT) AS PREV_CNT
  FROM ORD
 GROUP BY SHOP_NO, ORD_DT;

-- 주간 주문 추이
SELECT ORD_DT, ORD_CNT, ORD_CNT - PREV_CNT AS DIFF
  FROM V_SHOP_DAY
 WHERE SHOP_NO = :shop
   AND ORD_DT BETWEEN :d1 AND :d2
 ORDER BY ORD_DT;

실행계획 학습용 예시 ​

xplan
--------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |            |      1 |        |      7 |00:00:00.28 |   22422 |          |
|   1 |  SORT ORDER BY         |            |      1 |      7 |      7 |00:00:00.28 |   22422 | 2048  (0)|
|*  2 |   VIEW                 | V_SHOP_DAY |      1 |    730 |      7 |00:00:00.28 |   22422 |          |
|   3 |    WINDOW BUFFER       |            |      1 |    730 |    730 |00:00:00.28 |   22422 |36864  (0)|
|   4 |     SORT GROUP BY      |            |      1 |    730 |    730 |00:00:00.28 |   22422 |49152  (0)|
|*  5 |      TABLE ACCESS FULL | ORD        |      1 |   5000 |   5003 |00:00:00.27 |   22422 |          |
--------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(("ORD_DT">=:D1 AND "ORD_DT"<=:D2))
   5 - filter("SHOP_NO"=:SHOP)

문제 ​

  1. 매장 조건은 5번 줄까지 들어갔는데 날짜 조건은 2번 줄 VIEW에 남은 이유를 뷰 정의의 LAG와 관련지어 설명하시오. 조민우가 날짜 조건을 뷰 안에 그대로 넣었을 때 첫날 증감이 빈 이유도 설명하시오.
  2. 결과(첫날의 전일 대비 증감 포함)가 바뀌지 않게, 주문을 그 주 언저리만 인덱스로 읽도록 SQL을 고치시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자