테마
3월 28일 분기 누적 화면 사고(통계의 최댓값 밖 추정) 뒤에 박팀장이 정책을 정하라고 했다. "T_ORD_BIG처럼 날마다 자라는 테이블은 통계를 어떻게 지킬지, 근거를 붙여서." 주문은 매일 01:00 적재 배치가 전날 주문 약 913건을 일반 INSERT로 싣는다. 3월 31일에 손으로 다시 모은 뒤로 통계는 그대로다.
세 사람이 안을 냈다. 오과장은 적재 배치 끝에서 매일 모으자고 했고, 정하은은 STALE_PERCENT를 10에서 1로 낮춰 자동 수집에 맡기자고 했다. 조민우는 인터넷에서 본 방법이라며 분기 첫날마다 ORD_DT의 최댓값을 그 분기 말일로 올려 두자고 했다. 조민우가 4월 14일(월) 복사본에서 세 안을 재 왔다.
T_ORD_BIG: 4월 14일 현재 1,094,039행 · 약 6,373블록 · 매일 01:00에 전날 주문 약 913건IX_ORD_BIG_DT_CUS_AMT (ORD_DT, CUS_ID, ORD_AMT) · IX_ORD_BIG_CUS_DT (CUS_ID, ORD_DT) · IX_ORD_BIG_ST_DT (ORD_ST, ORD_DT)NUM_ROWS 1,081,257 · ORD_DT 최댓값 2025-03-30 · NUM_DISTINCT 1,184 · 히스토그램 없음M_CUS 2,000행 · 30블록 · M_RGN 8행TRUNC(SYSDATE) - 1 이상 TRUNC(SYSDATE) 미만) (C) 고객 30일 주문 이력(CUS_ID = :c AND ORD_DT >= TRUNC(SYSDATE) - 30)-- 지금 : 매일 01:00 주문 적재 (일반 INSERT · 통계는 자동 수집에 맡긴다 · STALE_PERCENT 10)
BEGIN
INSERT INTO T_ORD_BIG (ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT)
SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT
FROM STG_ORD_DAY; -- 전날 주문 약 913건
COMMIT;
END;
/
-- 안 ① 오과장 : 적재 뒤에 매일 모은다
-- DBMS_STATS.GATHER_TABLE_STATS(USER, 'T_ORD_BIG');
-- 안 ② 정하은 : 자동 수집이 더 자주 돌게 한다
-- DBMS_STATS.SET_TABLE_PREFS(USER, 'T_ORD_BIG', 'STALE_PERCENT', '1');
-- 안 ③ 조민우 : 분기 첫날마다 ORD_DT 최댓값을 그 분기 말일로 올려 둔다 (NUM_ROWS · NDV 는 그대로)
-- DBMS_STATS.SET_COLUMN_STATS(USER, 'T_ORD_BIG', 'ORD_DT', srec => ...);
[(A) 분기 누적 · 4월 14일 · 지금 통계]
------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 8 |00:00:00.02 | 12180 |
| 1 | HASH GROUP BY | | 1 | 8 | 8 |00:00:00.02 | 12180 |
|* 2 | HASH JOIN | | 1 | 913 | 11869 |00:00:00.02 | 12180 |
| 3 | TABLE ACCESS FULL | M_RGN | 1 | 8 | 8 |00:00:00.01 | 4 |
| 4 | NESTED LOOPS | | 1 | 913 | 11869 |00:00:00.02 | 12176 |
| 5 | NESTED LOOPS | | 1 | 913 | 11869 |00:00:00.01 | 307 |
|* 6 | INDEX RANGE SCAN | IX_ORD_BIG_DT_CUS_AMT | 1 | 913 | 11869 |00:00:00.01 | 57 |
|* 7 | INDEX UNIQUE SCAN | PK_M_CUS | 11869 | 1 | 11869 |00:00:00.01 | 250 |
| 8 | TABLE ACCESS BY INDEX ROWID| M_CUS | 11869 | 1 | 11869 |00:00:00.01 | 11869 |
------------------------------------------------------------------------------------------------------------
2 - access("R"."RGN_ID"="C"."RGN_ID")
6 - access("O"."ORD_DT">=TO_DATE(' 2025-04-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"O"."ORD_DT"<TO_DATE(' 2025-07-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
7 - access("C"."CUS_ID"="O"."CUS_ID")
[복사본 측정 · 4월 14일 · E-Rows / A-Rows]
지금(3/31 수집) ① 매일 수집 ② STALE 1 % ③ 최댓값 6/30
(A) 분기 누적 913 / 11,869 11,872 / 11,869 10,046 / 11,869 * 77,180 / 11,869
(B) 어제 913 / 913 913 / 913 913 / 913 1,762 / 913
(C) 고객 30일 7 / 14 14 / 14 13 / 14 45 / 14
(A)의 계획 NL · 12,180 HASH · 91 HASH · 91 HASH · 91
* ②는 4월 12일(토) 06:00 자동 수집 뒤의 값이다. 바뀐 행이 1%(10,813행)를 넘은 것은 4월 12일 01:00 적재 때였다.
4월 10일에는 (A)가 913 / 8,217로 NL · 8,434블록이었다.
③의 통계는 4월 1일 SET_COLUMN_STATS 뒤 그대로다(NUM_ROWS 1,081,257 · NUM_DISTINCT 1,184).