테마
유통 본사의 판매 화면들은 로그인한 사용자가 볼 수 있는 매장만 보여 준다. 권한 확인은 공통 함수 FN_CAN_SEE(사용자, 매장)가 하고, 화면 SQL마다 WHERE 절에 FN_CAN_SEE(:usr, h.SHP_NO) = 'Y'가 붙어 있다.
명동점 관리자가 한 달 판매 목록을 열면 자기 매장 4,176건이 나오는 데 0.6초가 걸린다. 다섯 매장 20,864건을 보는 본사 직원과 시간이 같다. 유통지원팀장은 함수가 붙은 SQL 세 개를 보고, 고칠 것과 필요한 인덱스를 정해 달라고 했다.
CF10 판매: 500,000행 · 4,583블록(블록당 약 109행) · SLE_DT VARCHAR2(8) · 날짜순으로 쌓였다 · 2023년 12월 20,864건, 그중 명동점(SHP_NO 1003) 4,176건CF11 판매상품: 1,096,708행 · 8,204블록 · CF11_PK (SLE_NO, ITM_NO) · 영수증 한 장에 평균 2.2행CF10_PK (SLE_NO) · 이 문제에서는 IX_CF10_SLE_DT (SLE_DT)도 있다 · 통계 최신T_USR_SHP 사용자별 조회 가능 매장(이 문제에서 쓰는 테이블): 72행 · 4블록 · PK_T_USR_SHP (USR_ID, SHP_NO) · 매장 관리자 5명은 한 곳, 지역 담당 3명은 두세 곳, 본사 직원 12명은 다섯 곳CREATE OR REPLACE FUNCTION FN_CAN_SEE(p_usr_id VARCHAR2, p_shp_no NUMBER) RETURN VARCHAR2 IS
v_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO v_cnt
FROM T_USR_SHP
WHERE USR_ID = p_usr_id
AND SHP_NO = p_shp_no;
RETURN CASE WHEN v_cnt > 0 THEN 'Y' ELSE 'N' END;
END;
/
-- [Q1] 판매 목록 (매장 관리자 · 지역 담당 · 본사, 하루 2,400번 · 보통 한 달)
SELECT h.SLE_NO, h.SLE_DT, h.SLE_HMS, h.SHP_NO
FROM CF10 h
WHERE h.SLE_DT BETWEEN :fr AND :to
AND FN_CAN_SEE(:usr, h.SHP_NO) = 'Y'
ORDER BY h.SLE_DT, h.SLE_HMS;
-- [Q2] 매장 상품 판매 합계 (하루 60번 · 한 달)
SELECT d.ITM_NO, SUM(d.SLE_QTY) AS qty
FROM CF10 h, CF11 d
WHERE h.SLE_DT BETWEEN :fr AND :to
AND FN_CAN_SEE(:usr, h.SHP_NO) = 'Y'
AND d.SLE_NO = h.SLE_NO
GROUP BY d.ITM_NO;
-- [Q3] 영수증 상세 (하루 9,000번 · 한 장)
SELECT h.SLE_NO, h.SLE_DT, h.SHP_NO, d.ITM_NO, d.SLE_QTY, d.SLE_UPRC
FROM CF10 h, CF11 d
WHERE h.SLE_NO = :sle_no
AND FN_CAN_SEE(:usr, h.SHP_NO) = 'Y'
AND d.SLE_NO = h.SLE_NO;
[Q1: DISPLAY_CURSOR (ALLSTATS LAST) · 명동점 관리자 · 2023년 12월]
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 4176 |00:00:00.61 | 295 | |
| 1 | SORT ORDER BY | | 1 | 208 | 4176 |00:00:00.61 | 295 | 407K (0)|
|* 2 | TABLE ACCESS BY INDEX ROWID BATCHED| CF10 | 1 | 208 | 4176 |00:00:00.60 | 295 | |
|* 3 | INDEX RANGE SCAN | IX_CF10_SLE_DT | 1 | 20833 | 20864 |00:00:00.01 | 98 | |
-----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("FN_CAN_SEE"(:USR,"H"."SHP_NO")='Y')
3 - access("H"."SLE_DT">=:FR AND "H"."SLE_DT"<=:TO)
[함수 안 SQL (dep=1) · SQL 한 번씩 · 명동점 관리자]
함수 호출 함수 안 SQL 블록 SQL 전체 경과 논리 읽기(합)
[Q1] 20,864 41,728 0.61 초 42,023
[Q2] 20,864 41,728 0.68 초 58,741
[Q3] 1 2 1 ms 7
(본사 직원이 열어도 [Q1]의 함수 호출은 20,864번으로 같다)