테마
버거 개발팀은 무한 스크롤 목록 화면을 FIRST_ROWS(20) 힌트로 고친 사례(OPT-035)를 보고 "목록 화면에는 FIRST_ROWS(20)을 넣는다"는 규칙을 만들어 점주 앱의 세 화면에 같은 힌트를 넣었다.
결과는 제각각이었다. A 「주문 목록」은 빨라졌다. B 「상품별 최근 판매」는 잘 팔리는 상품을 고르면 빠른데, 단종 상품을 고르면 3초씩 걸린다. C 「이번 달 판매 상위 10개 상품」(본사 화면)은 힌트를 넣기 전과 똑같이 0.6초다. 박팀장은 규칙을 다시 쓰라고 했다. "어떤 화면에 그 힌트가 통하는지 기준을 주세요."
ORD: 1,000,000행 · 22,422블록 · ORD_X01 (ORD_DT, ORD_HMS) · ORD_X02 (SHOP_NO, ORD_DT, ORD_HMS) · 한 달 약 41,700건ORD_ITEM: 2,472,717행 · 55,265블록 · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS) 리프 9,150블록 · 날짜순 적재(클러스터링 팩터 약 55,000) · 대부분 버퍼 캐시에 없다ORD_ITEM.ORD_DT는 주문의 ORD_DT를 그대로 복사한 컬럼이다.-- A 「주문 목록」 (매장, 최신순 · 무한 스크롤)
SELECT /*+ FIRST_ROWS(20) */ ORD_NO, ORD_DT, ORD_HMS
FROM ORD
WHERE SHOP_NO = :shop
ORDER BY ORD_DT DESC, ORD_HMS DESC;
-- B 「상품별 최근 판매」 (상품을 골라 최신순 · 무한 스크롤)
SELECT /*+ FIRST_ROWS(20) */ ORD_NO, ORD_DT, ORD_HMS, ORD_ITEM_QTY
FROM ORD_ITEM
WHERE ITEM_ID = :item
ORDER BY ORD_DT DESC, ORD_HMS DESC;
-- C 「이번 달 판매 상위 10개 상품」 (전 매장)
SELECT /*+ FIRST_ROWS(20) */ i.ITEM_ID, SUM(i.ORD_ITEM_QTY) AS qty
FROM ORD o, ORD_ITEM i
WHERE o.ORD_DT BETWEEN :d1 AND :d2
AND i.ORD_NO = o.ORD_NO
GROUP BY i.ITEM_ID
ORDER BY qty DESC
FETCH FIRST 10 ROWS ONLY;
[요약 — 첫 화면 기준]
A INDEX RANGE SCAN DESCENDING ORD_X02 + 테이블 20행 · 23블록 · 0.01초
B 잘 팔리는 상품 : INDEX FULL SCAN DESCENDING ORD_ITEM_X01 · 인덱스 1,840줄을 읽고 20행 · 52블록
단종 상품 : 같은 계획 · 아래
C 힌트 전과 같은 계획 : HASH GROUP BY ← HASH JOIN (ORD 한 달 · ORD_ITEM FULL) · 56,336블록 · 0.6초
[B — 단종 상품 · 첫 화면 20행]
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 20 |00:00:03.12 | 48330 | 41870 |
|* 1 | TABLE ACCESS BY INDEX ROWID| ORD_ITEM | 1 | 20 | 20 |00:00:03.12 | 48330 | 41870 |
| 2 | INDEX FULL SCAN DESCENDING| ORD_ITEM_X01 | 1 | 1840 | 1854K|00:00:00.58 | 6870 | 6020 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ITEM_ID"=:ITEM)