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

판매 검색 목록은 바로 뜨는데 「총 n건」 칸만 늘 한 박자 늦게 채워진다

기초SELECT유통331 / 700

상황 ​

본사 매장관리팀의 「판매 검색」은 매장과 기간을 넣으면 최근 판매부터 한 쪽에 20건을 보여 주고, 위에 「총 n건」을 띄운다. 기간의 기본값이 최근 1년이라 대부분 그대로 검색한다. 화면은 목록 SQL과 건수 SQL을 따로 보내는데, 목록은 바로 뜨고 건수 칸만 늦게 채워진다. 검색은 하루 약 6,000번이다. 매장관리팀장에게 물으니 건수는 "검색 조건이 너무 넓은지 가늠하는 데" 쓴다. 1,000건이 넘으면 조건을 좁히라고 안내하고 있다.

테이블과 인덱스 ​

  • CF10 판매: 500,000행 · 4,583블록 · SLE_DT VARCHAR2(8) 2022-01-01 ~ 2023-12-31(하루 약 685건, 날짜순으로 쌓여 있다) · SHP_NO 매장 6곳(고르게 나뉜다)
  • 인덱스: CF10_PK (SLE_NO) · IX_CF10_SLE_DT (SLE_DT)(리프 1,393블록, 한 블록에 약 360개)
  • 최근 1년의 한 매장 판매는 약 41,700건이다. 통계는 최신이다.

원본 SQL ​

sql
-- 목록 : 매장 하나 · 최근 1년 · 최신 20건
SELECT SLE_NO, SLE_DT, SLE_HMS
  FROM (SELECT SLE_NO, SLE_DT, SLE_HMS
          FROM CF10
         WHERE SHP_NO = :shp
           AND SLE_DT BETWEEN :from_dt AND :to_dt
         ORDER BY SLE_NO DESC)
 WHERE ROWNUM <= 20;

-- 총건수
SELECT COUNT(*)
  FROM CF10
 WHERE SHP_NO = :shp
   AND SLE_DT BETWEEN :from_dt AND :to_dt;

실행계획 학습용 예시 ​

xplan
[목록]
---------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |         |      1 |        |     20 |00:00:00.01 |       5 |
|*  1 |  COUNT STOPKEY                 |         |      1 |        |     20 |00:00:00.01 |       5 |
|   2 |   VIEW                         |         |      1 |     20 |     20 |00:00:00.01 |       5 |
|*  3 |    TABLE ACCESS BY INDEX ROWID | CF10    |      1 |  41667 |     20 |00:00:00.01 |       5 |
|   4 |     INDEX FULL SCAN DESCENDING | CF10_PK |      1 |    120 |    121 |00:00:00.01 |       3 |
---------------------------------------------------------------------------------------------------

[총건수]
---------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |         |      1 |        |      1 |00:00:00.06 |    4583 |
|   1 |  SORT AGGREGATE                |         |      1 |      1 |      1 |00:00:00.06 |    4583 |
|*  2 |   FILTER                       |         |      1 |        |  41682 |00:00:00.06 |    4583 |
|*  3 |    TABLE ACCESS FULL           | CF10    |      1 |  41667 |  41682 |00:00:00.06 |    4583 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
  [목록]   1 - filter(ROWNUM<=20)
           3 - filter(("SHP_NO"=:SHP AND "SLE_DT">=:FROM_DT AND "SLE_DT"<=:TO_DT))
  [총건수] 2 - filter(:FROM_DT<=:TO_DT)
           3 - filter(("SHP_NO"=:SHP AND "SLE_DT">=:FROM_DT AND "SLE_DT"<=:TO_DT))

문제 ​

  1. 목록은 5블록인데 건수 SQL은 왜 4,583블록을 읽는지 두 SQL의 차이로 설명하시오.
  2. 건수의 쓰임새에 맞게 건수 SQL을 고치고, 고친 SQL이 몇 블록을 읽을지와 그렇게 읽으려면 무엇을 확인해야 하는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자