Skip to content
튜닝 연습인덱스 스캔 효율과 테이블 액세스
ACC-051

재고 이력을 IOT로 바꾼 뒤 상품 재고 추이는 빨라졌는데, 일자별 재고 점검은 9블록에서 1,640블록이 됐다

중급SELECT유통126 / 700

상황 ​

본사 레거시 유통은 매일 밤 매장별 상품 재고를 한 줄씩 남기는 재고 이력 테이블을 둔다. 점장 앱의 「상품 재고 추이」(매장 하나, 상품 하나, 석 달)가 느려서, 석 달 전 오과장이 이 테이블을 PK 순서로 저장하는 IOT로 다시 만들었다. 그 화면은 93블록에서 3블록이 됐다. 그런데 재고 담당이 매일 아침 여는 「일자별 재고 점검」(하루 545줄)은 IOT로 바꾼 직후 9블록에서 550블록이 됐고, 지금은 1,640블록을 읽는다. 본사 담당 여럿이 하루 300번쯤 연다.

테이블과 인덱스 ​

  • CF18_HIS 일별상품재고 이력: CF18과 같은 컬럼(SHP_NO · ITM_NO · INV_BS_DT VARCHAR2(8) · INV_QTY)으로 2년 치를 쌓았다(이 문제를 위해 둔 파생 테이블) · 매장 5곳 × 상품 109개 × 730일 = 397,850행 · 하루 545줄
  • 석 달 전 IOT로 다시 만들었다 · PK CF18_HIS_PK (SHP_NO, ITM_NO, INV_BS_DT) · BLEVEL 2 · 리프는 만들 때 1,530블록, 지금 약 2,300블록
  • 밤마다 545줄이 매장과 상품 구간마다 끝에 하나씩, 즉 IOT의 가운데 545곳에 들어간다
  • 보조 인덱스 CF18_HIS_X01 (INV_BS_DT): IOT와 함께 만들었다 · BLEVEL 2 · 리프 약 1,900블록 · PCT_DIRECT_ACCESS는 만들 때 100, 지금 38 · 통계는 매주 일요일에 모은다
  • IOT로 바꾸기 전에는 힙 테이블에 같은 PK와 (INV_BS_DT) 인덱스가 있었고, 하루 545줄은 밤에 한꺼번에 들어가 4블록에 모여 있었다

원본 SQL ​

sql
SELECT SHP_NO, ITM_NO, INV_QTY
  FROM CF18_HIS
 WHERE INV_BS_DT = :v_dt
 ORDER BY SHP_NO, ITM_NO

실행계획 학습용 예시 · 이력 테이블은 CF18을 2년 치로 쌓았다고 둔 파생 테이블 ​

xplan
[지금 · PCT_DIRECT_ACCESS 38]
----------------------------------------------------------------------------------------------
| Id  | Operation             | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |              |      1 |        |    545 |00:00:00.01 |    1640 |
|   1 |  SORT ORDER BY        |              |      1 |    545 |    545 |00:00:00.01 |    1640 |
|   2 |   INDEX UNIQUE SCAN   | CF18_HIS_PK  |      1 |    545 |    545 |00:00:00.01 |    1640 |
|*  3 |    INDEX RANGE SCAN   | CF18_HIS_X01 |      1 |    545 |    545 |00:00:00.01 |       5 |
----------------------------------------------------------------------------------------------

[IOT로 바꾼 다음 날 · PCT_DIRECT_ACCESS 100]
----------------------------------------------------------------------------------------------
| Id  | Operation             | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |              |      1 |        |    545 |00:00:00.01 |     550 |
|   1 |  SORT ORDER BY        |              |      1 |    545 |    545 |00:00:00.01 |     550 |
|   2 |   INDEX UNIQUE SCAN   | CF18_HIS_PK  |      1 |    545 |    545 |00:00:00.01 |     550 |
|*  3 |    INDEX RANGE SCAN   | CF18_HIS_X01 |      1 |    545 |    545 |00:00:00.01 |       5 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("INV_BS_DT"=:V_DT)

[USER_INDEXES]
INDEX_NAME      PCT_DIRECT_ACCESS  IOT_REDUNDANT_PKEY_ELIM
CF18_HIS_X01                   38  YES

문제 ​

  1. 3번 줄로 545줄의 위치를 찾은 뒤 2번 줄이 1,640블록을 읽는 이유를, IOT의 보조 인덱스가 행을 가리키는 방식과 PCT_DIRECT_ACCESS로 설명하시오. 힙 테이블일 때 9블록이던 SQL이 IOT로 바꾼 다음 날에도 550블록이었던 이유도 설명하시오.
  2. IOT는 그대로 두고 이 점검이 IOT를 찾아가지 않도록 고치시오. 추측 주소(physical guess)를 갱신하는 방법과 비교하여 고른 방법의 대가를 설명하시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자