Skip to content
튜닝 연습파티션
PART-006

구 POS 판매까지 보이게 통합 뷰로 바꾼 뒤 매장 판매 이력이 0.01초에서 0.09초가 되었다

중급SELECT유통381 / 700

상황 ​

본사 영업관리팀의 「매장 판매 이력」 화면은 매장과 기간을 고르면 일자별 판매 건수를 보여 준다. 매장 담당자들이 하루 수백 번 연다. 지난달 조민우가 구 POS 시절의 2021년 판매(CF10_ARC)도 같은 화면에서 보이도록 두 테이블을 합친 통합 뷰 V_SLE_HIST를 만들고, 화면이 그 뷰를 읽게 바꿨다. 처음 만든 뷰는 UNION ALL에서 ORA-01790으로 거부되어 한 줄을 고쳐 다시 만들었다. 그 뒤로 2023년 6월 한 달을 고르면 0.01초이던 화면이 0.09초가 되었다. 화면 SQL에는 함수도 형변환도 없다.

테이블과 인덱스 ​

  • CF10_P 판매(파티션 복사본, 문제 설정): CF10 500,000행을 PARTITION BY RANGE (SLE_DT) 월별 24칸(P202201 ~ P202312)과 빈 PMAX로 나눠 CTAS로 지었다. 칸 하나는 약 20,800행이고 FULL로 약 192블록, 24칸 전체는 약 4,610블록이다. P202306은 18번째 칸이다. SLE_DT는 VARCHAR2(8) '20230615'이다.
  • CF10_ARC 판매 보관(문제 설정): 구 POS에서 옮긴 2021년 판매 249,600행 · 2,290블록. 컬럼은 CF10과 같지만 SLE_DT가 NUMBER(8) 20210615이다. 앞으로 DML이 없다. 인덱스 CF10_ARC_X01 (SLE_DT): BLEVEL 1.
  • 매장은 6곳이고 한 매장의 한 달 판매는 약 3,470건이다. CF10_P에는 이 조회에 쓸 인덱스가 없다. 통계는 최신이다.
  • 화면은 뷰의 SLE_DT가 숫자라서 기간을 숫자(:v_from = 20230601, :v_to = 20230630)로 넘긴다.

원본 SQL ​

sql
-- 통합 판매 이력 뷰 (ORA-01790 이 난 뒤 고쳐 만든 판)
CREATE OR REPLACE VIEW V_SLE_HIST AS
SELECT SLE_NO, TO_NUMBER(SLE_DT) AS SLE_DT, SLE_HMS, SHP_NO
  FROM CF10_P
UNION ALL
SELECT SLE_NO, SLE_DT, SLE_HMS, SHP_NO
  FROM CF10_ARC;

-- 「매장 판매 이력」 화면
SELECT SLE_DT, COUNT(*) AS sle_cnt
  FROM V_SLE_HIST
 WHERE SHP_NO = :v_shp
   AND SLE_DT BETWEEN :v_from AND :v_to
 GROUP BY SLE_DT
 ORDER BY SLE_DT

실행계획 학습용 예시 ​

xplan
-------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name         | Starts | E-Rows | A-Rows |      A-Time | Buffers | Pstart | Pstop |
-------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |              |      1 |        |     30 | 00:00:00.09 |    4612 |        |       |
|   1 |  SORT GROUP BY                           |              |      1 |     85 |     30 | 00:00:00.09 |    4612 |        |       |
|   2 |   VIEW                                   | V_SLE_HIST   |      1 |    312 |   3468 | 00:00:00.09 |    4612 |        |       |
|   3 |    UNION-ALL                             |              |      1 |        |   3468 | 00:00:00.09 |    4612 |        |       |
|*  4 |     FILTER                               |              |      1 |        |   3468 | 00:00:00.09 |    4610 |        |       |
|   5 |      PARTITION RANGE ALL                 |              |      1 |    208 |   3468 | 00:00:00.09 |    4610 |      1 |    25 |
|*  6 |       TABLE ACCESS FULL                  | CF10_P       |     24 |    208 |   3468 | 00:00:00.08 |    4610 |      1 |    25 |
|*  7 |     FILTER                               |              |      1 |        |      0 | 00:00:00.01 |       2 |        |       |
|*  8 |      TABLE ACCESS BY INDEX ROWID BATCHED | CF10_ARC     |      1 |    104 |      0 | 00:00:00.01 |       2 |        |       |
|*  9 |       INDEX RANGE SCAN                   | CF10_ARC_X01 |      1 |    624 |      0 | 00:00:00.01 |       2 |        |       |
-------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   4 - filter(:V_FROM<=:V_TO)
   6 - filter(("SHP_NO"=:V_SHP AND TO_NUMBER("SLE_DT")>=:V_FROM AND TO_NUMBER("SLE_DT")<=:V_TO))
   7 - filter(:V_FROM<=:V_TO)
   8 - filter("SHP_NO"=:V_SHP)
   9 - access("SLE_DT">=:V_FROM AND "SLE_DT"<=:V_TO)

[바인드 — V$SQL_BIND_CAPTURE]
   NAME     DATATYPE_STRING  VALUE_STRING
   :V_FROM  NUMBER           20230601
   :V_TO    NUMBER           20230630

문제 ​

  1. 화면 SQL에는 함수가 없는데 CF10_P의 칸을 전부 여는 까닭을 Predicate Information과 뷰 정의로 설명하시오. 뷰를 만든 사람이 왜 그렇게 고쳤는지도 쓰시오.
  2. 결과가 바뀌지 않게 뷰를 고쳐 6월 칸 하나만 읽게 하시오. 그때 보관 테이블 쪽 갈래가 어떻게 되는지와 그것을 처리하는 방법도 쓰시오.
  3. 뷰를 고친 뒤 화면 쪽에서 함께 바꿔야 할 것과 Buffers가 어떻게 바뀌는지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자