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

인덱스를 만들고 진화 작업까지 돌렸는데 진화할 계획이 하나도 없다고 나온다

기초PLSQL이커머스640 / 700

이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.

상황 ​

이커머스 고객센터의 「포인트 내역」 화면은 고객 한 명의 포인트 거래를 최신순으로 보여 준다. 상담원이 하루 약 2만 번 연다. 지난주 DBA가 이 화면을 위해 (customer_id, created_at) 인덱스를 만들었는데 계획은 그대로 FULL이다. Note에는 베이스라인 줄이 있다. 2023년 3월 사이트를 열 때 외주 업체가 상위 SQL 30개를 베이스라인으로 올리면서 "오픈 직후 계획이 흔들리지 않게" 고정해 두었다는 기록이 있다. 조민우는 18화에서 배운 대로 진화 작업을 돌렸지만, 리포트에는 검증할 계획이 없다는 말뿐이었다.

테이블과 인덱스 ​

  • point_transactions: 45,000행 · 210블록 · 고객 5,230명 · 고객당 약 9건 · tx_type(EARN · USE · EXPIRE)
  • 인덱스: PK (tx_id) · 지난주에 만든 IX_PT_CUS_DT (customer_id, created_at) · 통계 최신
  • 대조: 같은 날 만든 IX_RV_PRD (product_id) 덕을 볼 「상품 리뷰 목록」 SQL도 2023년 3월에 같은 방식으로 베이스라인을 올렸다

원본 SQL ​

sql
-- 2023-03-02 오픈 대비 (외주 업체) : 상위 SQL 의 계획을 올리고 고정한다
DECLARE
  n PLS_INTEGER;
BEGIN
  n := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id => '9w1n4c7t2k8dq');
  n := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(sql_handle      => 'SQL_6r2k8x1v9c0a5f',
                                        attribute_name  => 'FIXED',
                                        attribute_value => 'YES');
END;
/

-- 지난주 (DBA) : 포인트 내역 화면용 인덱스
CREATE INDEX IX_PT_CUS_DT ON point_transactions (customer_id, created_at);

-- 어제 (조민우) : 진화 작업
DECLARE
  t VARCHAR2(128);
  e VARCHAR2(128);
BEGIN
  t := DBMS_SPM.CREATE_EVOLVE_TASK(sql_handle => 'SQL_6r2k8x1v9c0a5f');
  e := DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name => t);
END;
/

-- 포인트 내역 화면 SQL (SQL_ID 9w1n4c7t2k8dq)
SELECT tx_id, tx_type, amount, created_at
  FROM point_transactions
 WHERE customer_id = :cid
 ORDER BY created_at DESC;

실행계획 학습용 예시 ​

xplan
[지금 계획 · ALLSTATS LAST]
Plan hash value: 3365107282

-----------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name               | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Used-Mem |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                    |      1 |        |      9 |00:00:00.01 |     211 |          |
|   1 |  SORT ORDER BY     |                    |      1 |      9 |      9 |00:00:00.01 |     211 | 2048  (0)|
|*  2 |   TABLE ACCESS FULL| POINT_TRANSACTIONS |      1 |      9 |      9 |00:00:00.01 |     211 |          |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("CUSTOMER_ID"=:CID)

Note
-----
   - SQL plan baseline "SQL_PLAN_6r2k8x1v9c0a5f3d2b17" used for this statement

[DBA_SQL_PLAN_BASELINES]
 SQL_HANDLE          PLAN_NAME                      ORIGIN                         ENABLED ACCEPTED FIXED CREATED
 SQL_6r2k8x1v9c0a5f  SQL_PLAN_6r2k8x1v9c0a5f3d2b17  MANUAL-LOAD-FROM-CURSOR-CACHE  YES     YES      YES   23-03-02
 (대조 · 상품 리뷰 목록)
 SQL_2c9e4d7a1b3f60  SQL_PLAN_2c9e4d7a1b3f60e10a77  MANUAL-LOAD-FROM-CURSOR-CACHE  YES     YES      NO    23-03-02
 SQL_2c9e4d7a1b3f60  SQL_PLAN_2c9e4d7a1b3f6044c19a  AUTO-CAPTURE                   YES     NO       NO    24-10-22

[진화 리포트 요약 · 어제 · 포인트 내역 SQL]
 검증한 계획 0개 · 이 문장의 계획 이력에 ACCEPTED = NO 인 계획이 없다

문제 ​

  1. 인덱스를 만들고 진화 작업을 돌렸는데도 검증할 계획이 하나도 없는 이유를 베이스라인 목록으로 설명하시오. 대조로 적은 상품 리뷰 목록 SQL과 무엇이 다른지도 쓰시오.
  2. 인덱스 계획이 검사를 거쳐 쓰이도록 SQL로 고치고, 앞으로 FIXED를 어떻게 다룰지 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자