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

운영 상황판의 「최근 30일 판매 품목 수」가 열 때마다 주문상품 인덱스를 통째로 읽는다

중급SELECT버거341 / 700

상황 ​

본사 운영실 상황판에는 최근 30일의 일별 판매 품목 수(주문상품 줄 수) 막대그래프가 있다. 상황판 PC 8대가 5분마다 새로 고쳐 하루 약 2,300번 호출된다. 개발자는 판매일 인덱스 ORD_ITEM_X01이 있으니 최근 날짜부터 30일 치만 읽고 멈출 것이라 생각해 ROWNUM <= 30을 걸었다. SQL은 본사 공통 집계 틀로 만들어서 /*+ USE_HASH_AGGREGATION */ 힌트가 붙어 있다. 이 틀은 2019년에 월 집계 하나가 정렬 집계로 TEMP를 넘긴 뒤 "집계는 해시로" 하라며 만든 것이다. DBA는 논리 읽기 상위 SQL에서 이 SQL을 찾았다. 실행할 때마다 0.2초가 걸리고 주문상품 인덱스를 통째로 읽는다.

테이블과 인덱스 ​

  • ORD_ITEM 주문상품: 2,472,717행 · 55,265블록 · ORD_NO · ITEM_ID · ORD_ITEM_QTY · ORD_DT VARCHAR2(8) NOT NULL · ORD_HMS VARCHAR2(6) NOT NULL · 2012-01-01 ~ 2013-12-31 · 하루 약 3,390줄 · 날짜순으로 쌓여 있다
  • 인덱스 ORD_ITEM_PK (ORD_NO, ITEM_ID), ORD_ITEM_X01 (ORD_DT, ORD_HMS): BLEVEL 2 · 리프 약 8,770블록(한 블록에 약 280개) · ORD_DT가 NOT NULL이라 모든 행이 이 인덱스에 있다
  • 통계는 최신이다.

원본 SQL ​

sql
SELECT ORD_DT, ITEM_LINES
  FROM (SELECT /*+ USE_HASH_AGGREGATION */
               ORD_DT, COUNT(*) AS ITEM_LINES
          FROM ORD_ITEM
         GROUP BY ORD_DT
         ORDER BY ORD_DT DESC)
 WHERE ROWNUM <= 30

실행계획 학습용 예시 ​

xplan
--------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |              |      1 |        |     30 |00:00:00.21 |    8812 |       |       |          |
|*  1 |  COUNT STOPKEY           |              |      1 |        |     30 |00:00:00.21 |    8812 |       |       |          |
|   2 |   VIEW                   |              |      1 |    730 |     30 |00:00:00.21 |    8812 |       |       |          |
|*  3 |    SORT ORDER BY STOPKEY |              |      1 |    730 |     30 |00:00:00.21 |    8812 |  9216 |  9216 | 8192  (0)|
|   4 |     HASH GROUP BY        |              |      1 |    730 |    730 |00:00:00.21 |    8812 |  1200K|  1200K| 1421K (0)|
|   5 |      INDEX FAST FULL SCAN| ORD_ITEM_X01 |      1 |   2472K|   2472K|00:00:00.09 |    8812 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=30)
   3 - filter(ROWNUM<=30)

문제 ​

  1. ROWNUM <= 30을 걸었는데도 5번 줄이 인덱스를 통째로 읽는 까닭을 4번 줄 HASH GROUP BY가 일하는 방식으로 설명하고, 해시로 묶게 만든 것이 무엇인지 쓰시오.
  2. 최근 30일 치 인덱스 항목만 읽고 멈추도록 고치고, 고친 뒤의 실행계획에서 무엇이 멈추게 하는지 설명하시오. 공통 틀의 힌트를 어떻게 다룰지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자