테마
본사 운영실 상황판에는 최근 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이라 모든 행이 이 인덱스에 있다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
--------------------------------------------------------------------------------------------------------------------------------
| 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)
ROWNUM <= 30을 걸었는데도 5번 줄이 인덱스를 통째로 읽는 까닭을 4번 줄 HASH GROUP BY가 일하는 방식으로 설명하고, 해시로 묶게 만든 것이 무엇인지 쓰시오.