테마
정산팀의 「기간별 상품 매출」은 처음에는 하루 범위로 쓰다가 올해부터 한 달 범위로 매일 50번쯤 돈다. 운영에서는 0.05초, 시험 DB(운영 복제)에서는 0.01초가 걸린다. 개발팀은 시험 DB의 계획 Outline으로 SQL 프로파일을 만들어 운영에 넣었다. 프로파일은 붙었는데 계획은 바뀌지 않았다.
작년 11월 업그레이드 주간에는 계획을 지키려고 OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES를 일주일 동안 켜 두었다. 시험 DB로는 데이터만 복제했고 SQL 관리 객체(베이스라인, 프로파일)는 옮기지 않았다.
T_ORD: 100,000행 · 896블록 · ORD_DT DATE(시분초 있음) · 한 달 약 2,740건 · IX_T_ORD_DT (ORD_DT)(날짜순 적재라 한 달 치가 약 25블록에 모여 있다) · PK_T_ORD (ORD_SEQ)T_ORD_DET: 200,000행 · 896블록 · PK_T_ORD_DET (ORD_SEQ, ORD_DET_NO) 높이 2 · 주문당 평균 2건-- 개발팀이 운영에 넣은 것 : 시험 DB 계획의 Outline 을 프로파일로
BEGIN
DBMS_SQLTUNE.IMPORT_SQL_PROFILE(
sql_text => :q_text, -- 아래 SQL 의 글자 그대로
profile => SQLPROF_ATTR('BEGIN_OUTLINE_DATA',
'IGNORE_OPTIM_EMBEDDED_HINTS',
'ALL_ROWS',
'INDEX_RS_ASC(@"SEL$1" "O"@"SEL$1" ("T_ORD"."ORD_DT"))',
'FULL(@"SEL$1" "D"@"SEL$1")',
'LEADING(@"SEL$1" "O"@"SEL$1" "D"@"SEL$1")',
'USE_HASH(@"SEL$1" "D"@"SEL$1")',
'END_OUTLINE_DATA'),
name => 'PROF_ITM_PERIOD',
force_match => TRUE);
END;
/
SELECT d.ITM_ID, SUM(d.ORD_QTY) AS qty, SUM(d.ORD_QTY * d.UNT_PRC) AS amt
FROM T_ORD o, T_ORD_DET d
WHERE o.ORD_DT >= :v_from
AND o.ORD_DT < :v_to
AND d.ORD_SEQ = o.ORD_SEQ
GROUP BY d.ITM_ID
[운영 — 6월 한 달 · 프로파일을 넣은 뒤]
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 100 |00:00:00.05 | 8273 |
| 1 | HASH GROUP BY | | 1 | 100 | 100 |00:00:00.05 | 8273 |
|* 2 | FILTER | | 1 | | 5480 |00:00:00.05 | 8273 |
| 3 | NESTED LOOPS | | 1 | 5480 | 5480 |00:00:00.04 | 8273 |
| 4 | NESTED LOOPS | | 1 | 5480 | 5480 |00:00:00.02 | 5515 |
| 5 | TABLE ACCESS BY INDEX ROWID BATCHED| T_ORD | 1 | 2740 | 2740 |00:00:00.01 | 35 |
|* 6 | INDEX RANGE SCAN | IX_T_ORD_DT | 1 | 2740 | 2740 |00:00:00.01 | 10 |
|* 7 | INDEX RANGE SCAN | PK_T_ORD_DET | 2740 | 2 | 5480 |00:00:00.01 | 5480 |
| 8 | TABLE ACCESS BY INDEX ROWID | T_ORD_DET | 5480 | 2 | 5480 |00:00:00.01 | 2758 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:V_FROM<:V_TO)
6 - access("O"."ORD_DT">=:V_FROM AND "O"."ORD_DT"<:V_TO)
7 - access("D"."ORD_SEQ"="O"."ORD_SEQ")
Note
-----
- SQL profile PROF_ITM_PERIOD used for this statement
- SQL plan baseline SQL_PLAN_5qh8mbn2xw3k1c9a4e07d used for this statement
[DBA_SQL_PLAN_BASELINES — 이 SQL]
SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED FIXED CREATED 계획
SQL_5c2f0a4e6b1d93a7 SQL_PLAN_5qh8mbn2xw3k1c9a4e07d AUTO-CAPTURE YES YES NO 2023-11-08 NL (PK_T_ORD_DET)
SQL_5c2f0a4e6b1d93a7 SQL_PLAN_5qh8mbn2xw3k17b61f2a0 AUTO-CAPTURE YES NO NO 2024-02-19 HASH (T_ORD_DET FULL)
[시험 DB — 같은 SQL · 베이스라인 없음] HASH JOIN · T_ORD_DET FULL · Buffers 931