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

월 판매 원장 화면이 일 판매 원장보다 줄은 적은데 한 쪽을 여는 데 스무 배 넘게 읽는다

기초SELECT유통340 / 700

상황 ​

본사 영업지원팀은 판매 원장을 두 화면으로 본다. 「일 판매 원장」은 고른 날부터 하루씩 31일을, 「월 판매 원장」은 고른 달부터 한 달씩 6개월을 한 쪽에 보여 주고, 「다음」을 누르면 이어서 보여 준다. 두 화면 모두 같은 개발자가 같은 틀로 짰다. 팀원들은 "월 원장은 한 쪽에 6줄뿐인데 31줄짜리 일 원장보다 늦다"고 한다. DBA가 재 보니 월 원장의 첫 쪽(2022년 1월부터)이 일 원장 첫 쪽의 스무 배 넘게 읽는다.

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) NOT NULL(2022-01-01 ~ 2023-12-31, 하루 약 685건, 한 달 약 2만 800건)
  • 인덱스 IX_CF10_SLE_DT (SLE_DT): BLEVEL 2 · 리프 1,393블록(한 블록에 약 360개) · 통계 최신

원본 SQL ​

sql
-- 월 판매 원장 : :from_dt 부터 6개월 (첫 쪽은 :from_dt = '20220101')
SELECT SUBSTR(SLE_DT, 1, 6) AS SLE_YM, COUNT(*) AS SLE_CNT
  FROM CF10
 WHERE SLE_DT >= :from_dt
 GROUP BY SUBSTR(SLE_DT, 1, 6)
 ORDER BY SLE_YM
 FETCH FIRST 6 ROWS ONLY;

-- 일 판매 원장 (비교용) : :from_dt 부터 31일
SELECT SLE_DT, COUNT(*) AS SLE_CNT
  FROM CF10
 WHERE SLE_DT >= :from_dt
 GROUP BY SLE_DT
 ORDER BY SLE_DT
 FETCH FIRST 31 ROWS ONLY;

실행계획 학습용 예시 · 식으로 묶으면 NOSORT가 사라지는 모양은 교재 환경 23ai에서 확인 ​

xplan
[월 판매 원장 · 첫 쪽]
-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                |      1 |        |      6 |00:00:00.09 |    1406 |       |       |          |
|*  1 |  COUNT STOPKEY          |                |      1 |        |      6 |00:00:00.09 |    1406 |       |       |          |
|   2 |   VIEW                  |                |      1 |    730 |      6 |00:00:00.09 |    1406 |       |       |          |
|*  3 |    SORT GROUP BY STOPKEY|                |      1 |    730 |      6 |00:00:00.09 |    1406 |  2048 |  2048 | 2048  (0)|
|*  4 |     INDEX FAST FULL SCAN| IX_CF10_SLE_DT |      1 |    500K|    500K|00:00:00.04 |    1406 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=6)
   3 - filter(ROWNUM<=6)
   4 - filter("SLE_DT">=:FROM_DT)

[일 판매 원장 · 첫 쪽]
-------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |                |      1 |        |     31 |00:00:00.01 |      61 |       |       |          |
|*  1 |  COUNT STOPKEY          |                |      1 |        |     31 |00:00:00.01 |      61 |       |       |          |
|   2 |   VIEW                  |                |      1 |     31 |     31 |00:00:00.01 |      61 |       |       |          |
|   3 |    SORT GROUP BY NOSORT |                |      1 |     31 |     31 |00:00:00.01 |      61 |       |       |          |
|*  4 |     INDEX RANGE SCAN    | IX_CF10_SLE_DT |      1 |    500K|  21236 |00:00:00.01 |      61 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(ROWNUM<=31)
   4 - access("SLE_DT">=:FROM_DT)

문제 ​

  1. 두 SQL이 같은 인덱스를 쓰는데 일 원장은 31일 치만 읽고 멈추고 월 원장은 끝까지 읽는 까닭을 3번 줄의 이름으로 설명하시오.
  2. 월 원장도 6개월 치만 읽도록 고치고, 다른 방법(함수 기반 인덱스, 그대로 두기)과 견주어 고른 까닭을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자