Skip to content
튜닝 연습옵티마이저와 통계
OPT-055

지운 자리를 돌려받으려고 주문상품 테이블을 재구성한 다음 날 아침, 주문 상세 화면이 한 번에 0.5초씩 걸린다

중급DDL버거645 / 700

상황 ​

버거 본사 POS DB는 Diagnostic Pack 계약이 없어서 AWR 대신 1시간마다 Statspack 스냅샷(level 7)을 찍는다(교재 17화). 일요일 밤 DBA가 2011년 시험 데이터 30만 줄을 지운 ORD_ITEM의 빈 공간을 돌려받으려고 테이블을 재구성했다. 월요일 아침부터 점장 화면 「주문 상세」(주문 번호로 상품 줄을 보는 화면, 하루 약 4,000번)가 한 번에 0.5초씩 걸린다. 오과장은 고개를 갸웃했다. "블록이 줄었으니 더 빨라져야 하는데요." POS 마감 적재는 매일 밤 23:30에 ORD와 ORD_ITEM에 전날 주문을 넣는다.

테이블과 인덱스 ​

  • ORD_ITEM: 지금 2,472,717행 · 55,265블록(재구성 전에는 2011년 줄 30만 개를 지운 빈자리까지 약 62,000블록) · ORD_ITEM_PK (ORD_NO, ITEM_ID) · ORD_ITEM_X01 (ORD_DT, ORD_HMS)
  • ITEM: 92행 · 5블록 · ITEM_PK (ITEM_ID)
  • SKIP_UNUSABLE_INDEXES 기본값(TRUE) · Statspack 1시간 간격 level 7(실행계획까지 남긴다)

원본 SQL ​

sql
-- 일요일 23:30 DBA 작업
DELETE FROM ORD_ITEM WHERE ORD_DT < '20120101';   -- 2011년 시험 데이터 300,000줄
COMMIT;
ALTER TABLE ORD_ITEM MOVE;                         -- 빈 공간을 돌려받는다
-- 통계는 자동 수집에 맡긴다

-- 점장 화면 「주문 상세」 (SQL_ID 6hd0k3w8z1q5m)
SELECT i.ITEM_ID, t.ITEM_NM, i.ORD_ITEM_QTY
  FROM ORD_ITEM i, ITEM t
 WHERE i.ORD_NO = :ord_no
   AND t.ITEM_ID = i.ITEM_ID;

실행계획 학습용 예시 ​

xplan
[Statspack SQL 보고서 (sprepsql.sql) · SQL_ID 6hd0k3w8z1q5m · 일 22:00 ~ 월 11:00]
 Snap Id  시작        Plan Hash Value  Executions  Buffer Gets  Gets/Exec  Physical Reads
   8841   일 22:00        1712459063          36          360       10.0               0
   8853   월 10:00         396217480         412   22,772,064   55,272.0      22,769,180
   8854   월 11:00         396217480         431   23,822,232   55,272.0      23,819,215

 Known Optimizer Plan(s) for this Old Hash Value
  1712459063 : NESTED LOOPS → TABLE ACCESS BY INDEX ROWID ORD_ITEM → INDEX RANGE SCAN ORD_ITEM_PK → TABLE ACCESS BY INDEX ROWID ITEM → INDEX UNIQUE SCAN ITEM_PK
   396217480 : NESTED LOOPS → TABLE ACCESS FULL ORD_ITEM → TABLE ACCESS BY INDEX ROWID ITEM → INDEX UNIQUE SCAN ITEM_PK

[DBA_OBJECTS · DBA_INDEXES]
 ORD_ITEM      TABLE  LAST_DDL_TIME 일 23:41
 ORD_ITEM_PK   INDEX  STATUS UNUSABLE
 ORD_ITEM_X01  INDEX  STATUS UNUSABLE

[지금 커서 · ALLSTATS LAST · 주문 하나]
Plan hash value: 396217480

------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |          |      1 |        |      3 |00:00:00.49 |   55272 |  55265 |
|   1 |  NESTED LOOPS                |          |      1 |      3 |      3 |00:00:00.49 |   55272 |  55265 |
|*  2 |   TABLE ACCESS FULL          | ORD_ITEM |      1 |      3 |      3 |00:00:00.49 |   55266 |  55265 |
|   3 |   TABLE ACCESS BY INDEX ROWID| ITEM     |      3 |      1 |      3 |00:00:00.01 |       6 |      0 |
|*  4 |    INDEX UNIQUE SCAN         | ITEM_PK  |      3 |      1 |      3 |00:00:00.01 |       3 |      0 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("I"."ORD_NO"=:ORD_NO)
   4 - access("T"."ITEM_ID"="I"."ITEM_ID")

문제 ​

  1. 팩이 없는 이 DB에서 계획이 언제, 무엇 때문에 바뀌었는지 위 자료로 설명하시오. 오류가 하나도 나지 않은 이유도 쓰시오.
  2. 지금 할 조치를 SQL로 쓰시오. 오늘 밤 23:30 적재 전에 꼭 끝내야 하는 이유와, 다음에 같은 재구성을 할 때의 방법도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자