테마
본사 유통의 협력사 포털 「상품별 월 판매」는 협력사 담당자가 자기 상품 가운데 볼 것을 체크하고 월을 고르면 상품마다 판매 수량과 금액을 보여 준다. 포털(Java)은 체크한 상품 번호를 SQL 컬렉션 타입 ITM_NO_TAB 하나로 바인드해 프로시저 PTNR_ITM_SALES를 부른다.
푸드 협력사(1005)는 상품 21종을 모두 체크하는 일이 많은데, 그러면 2.34초가 걸린다. 3종만 고르면 0.34초다. 개발자는 이렇게 말한다. "고르는 상품 수가 매번 달라서 한 문장으로는 못 짜고 상품마다 돌렸어요."
CF10 판매: 500,000행 · 4,583블록 · CF10_PK (SLE_NO) · SLE_DT VARCHAR2(8) · 2023년 12월 20,864건 · SLE_DT로 시작하는 인덱스는 이 문제에서 없다CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · ITM_NO로 시작하는 인덱스는 없다 · 2023년 12월 46,322줄ITM_NO 1047 ~ 1067): 판매상품 105,736줄(2년 치) · 2023년 12월 4,536줄ITM_NO_TAB: CREATE TYPE ITM_NO_TAB AS TABLE OF NUMBER로 만든 SQL 타입(스키마에 있다)TMP_PTNR_SALES: 임시 테이블(GTT) · ITM_NO · QTY · AMTPROCEDURE PTNR_ITM_SALES(p_itms IN ITM_NO_TAB, p_ym IN VARCHAR2, p_cur OUT SYS_REFCURSOR) IS
v_qty NUMBER;
v_amt NUMBER;
BEGIN
DELETE FROM TMP_PTNR_SALES;
FOR i IN 1 .. p_itms.COUNT LOOP -- 고른 상품마다
SELECT NVL(SUM(d.SLE_QTY), 0), NVL(SUM(d.SLE_QTY * d.SLE_UPRC), 0)
INTO v_qty, v_amt
FROM CF10 h, CF11 d
WHERE h.SLE_DT BETWEEN p_ym || '01' AND p_ym || '31'
AND d.SLE_NO = h.SLE_NO
AND d.ITM_NO = p_itms(i);
INSERT INTO TMP_PTNR_SALES (ITM_NO, QTY, AMT) VALUES (p_itms(i), v_qty, v_amt);
END LOOP;
OPEN p_cur FOR SELECT ITM_NO, QTY, AMT FROM TMP_PTNR_SALES ORDER BY ITM_NO;
END;
[포털 로그: 고른 상품 수별 경과 (2023년 12월)] 3종 0.34초 · 7종 0.78초 · 21종 2.34초
[V$SQL: 21종을 고른 호출 한 번]
SQL_TEXT EXECUTIONS BUFFER_GETS ELAPSED
SELECT NVL(SUM(D.SLE_QTY), 0), NVL(SUM(D.SLE_QTY * D.SLE_UPRC), 0) FROM … 21 268,527 2.31 초
INSERT INTO TMP_PTNR_SALES (ITM_NO, QTY, AMT) VALUES (:B3 , :B2 , :B1 ) 21 24 0.00 초
DELETE FROM TMP_PTNR_SALES 1 3 0.00 초
SELECT ITM_NO, QTY, AMT FROM TMP_PTNR_SALES ORDER BY ITM_NO 1 3 0.00 초
[루프 안 SELECT 한 번: ITM_NO = 1067 (DISPLAY_CURSOR · ALLSTATS LAST)]
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.11 | 12787 | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.11 | 12787 | |
|* 2 | HASH JOIN | | 1 | 519 | 272 |00:00:00.11 | 12787 | 1557K (0)|
|* 3 | TABLE ACCESS FULL| CF11 | 1 | 12463 | 6247 |00:00:00.06 | 8204 | |
|* 4 | TABLE ACCESS FULL| CF10 | 1 | 20833 | 20864 |00:00:00.03 | 4583 | |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."SLE_NO"="H"."SLE_NO")
3 - filter("D"."ITM_NO"=:B1)
4 - filter(("H"."SLE_DT">=:B3||'01' AND "H"."SLE_DT"<=:B2||'31'))
V$SQL과 실행계획의 숫자로 설명하시오.