테마
본사 레거시 유통의 매장 단말 6대는 「정산 보류 판매」 목록을 1분마다 새로 고친다(08:00 ~ 22:00, 하루 약 5,000번). 단말은 프로시저 PKG_SLE_HOLD.hold_list를 부르고, 넘기는 판매 구분은 늘 '90'(정산 보류)이다.
지난주 반품 정산 배치를 새로 연 뒤로 DBA가 이상한 모양을 보고했다. "오후 2시부터 이 조회가 Top SQL 1위로 올라오고, 다음 날 아침에는 아무 일 없었다는 듯 사라집니다. 배치가 2시에 같은 SQL을 한 번 부르기는 하지만 한 번뿐이고, 보류 목록 SQL은 아무도 손대지 않았어요."
CF10 판매: 500,000행 · 4,583블록 · SLE_NO VARCHAR2(15) · SLE_DT VARCHAR2(8) · SLE_HMS · SHP_NO · SLE_NO 순(날짜순)으로 적재SLE_DV_CD VARCHAR2(2) 판매 구분: '10' 정상 488,600건 · '20' 반품 11,300건 · '90' 정산 보류 100건 · FREQUENCY 히스토그램 · 반품과 보류는 날짜와 상관없이 테이블 곳곳에 흩어져 있다IX_CF10_DV_CD (SLE_DV_CD): 높이 3 · 리프 약 1,000블록no_invalidate => FALSE). 그래서 이 문장의 커서는 매일 밤 무효화되고, 그 뒤 첫 호출은 08:00 단말이다.NLS_LENGTH_SEMANTICS = BYTE · CURSOR_SHARING = EXACT · 바인드 피킹 켬-- PKG_SLE_HOLD.hold_list (2018) : 매장 단말이 1분마다 부른다 (단말은 늘 '90'을 넘긴다)
PROCEDURE hold_list(p_cd IN VARCHAR2, rc OUT SYS_REFCURSOR) IS
v_cd VARCHAR2(2) := p_cd;
BEGIN
OPEN rc FOR
SELECT SLE_NO, SLE_DT, SLE_HMS, SHP_NO
FROM CF10
WHERE SLE_DV_CD = v_cd;
END;
-- PKG_RTN_STLM.run (지난주 신규) : 반품 정산 · 매일 14:00에 한 번 · SQL은 위 패키지에서 복사했다
PROCEDURE run IS
v_cd VARCHAR2(100) := '20'; -- 구분 코드가 길어질지 몰라 넉넉하게
BEGIN
FOR r IN (SELECT SLE_NO, SLE_DT, SLE_HMS, SHP_NO
FROM CF10
WHERE SLE_DV_CD = v_cd) LOOP
ins_rtn_stlm(r.SLE_NO, r.SLE_DT, r.SHP_NO);
END LOOP;
COMMIT;
END;
[V$SQL · 16:00 · 텍스트 하나에 자식 둘]
SQL_TEXT : SELECT SLE_NO, SLE_DT, SLE_HMS, SHP_NO FROM CF10 WHERE SLE_DV_CD = :B1
CHILD IS_SHAREABLE :B1 MAX_LENGTH PLAN_HASH EXECUTIONS BUFFER_GETS/EXEC FIRST_LOAD_TIME 처음 부른 곳
0 N 32 2704158391 2,160 103 2023-06-15/08:00:04 PKG_SLE_HOLD.hold_list
1 Y 128 1186043257 721 4,587 2023-06-15/14:00:02 PKG_RTN_STLM.run
[V$SQL_SHARED_CURSOR · Y인 칸] child 1 : BIND_LENGTH_UPGRADEABLE = Y
[자식 0 · 단말 한 번 (08:00 ~ 13:59) · FORMAT 'ALLSTATS LAST +PEEKED_BINDS']
Plan hash value: 2704158391
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 100 |00:00:00.01 | 103 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED | CF10 | 1 | 100 | 100 |00:00:00.01 | 103 |
|* 2 | INDEX RANGE SCAN | IX_CF10_DV_CD | 1 | 100 | 100 |00:00:00.01 | 3 |
-------------------------------------------------------------------------------------------------------------
Peeked Binds (identified by name):
----------------------------------
1 - :B1 (VARCHAR2(32), CSID=873): '90'
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SLE_DV_CD"=:B1)
[자식 1 · 단말 한 번 (14:00 이후) · FORMAT 'ALLSTATS LAST +PEEKED_BINDS']
Plan hash value: 1186043257
-----------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 100 |00:00:00.04 | 4587 |
|* 1 | TABLE ACCESS FULL| CF10 | 1 | 11300 | 100 |00:00:00.04 | 4587 |
-----------------------------------------------------------------------------------
Peeked Binds (identified by name):
----------------------------------
1 - :B1 (VARCHAR2(128), CSID=873): '20'
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SLE_DV_CD"=:B1)
[그제와 어제도 같다] 08:00 자식 0('90', 인덱스) → 14:00 자식 1('20', FULL) → 01:00 통계 수집으로 무효화