테마
이 문제는 교재 18화 졸업 과제와 같은 이커머스 데이터베이스를 씁니다. 『튜너의 1년』을 순서대로 읽고 있다면 졸업 과제를 먼저 풀고 오세요. 아래 「테이블과 인덱스」 칸에 과제의 답 일부(제약 조건, 인덱스, 통계의 실제 상태)가 나옵니다.
관리자 화면의 「주문상품 내려받기」는 한 해 치 주문상품을 카테고리명과 함께 파일로 내려 준다. 카테고리명은 함수 fn_category_name이 붙인다. 느리다는 말에 개발자는 블로그 글을 보고 함수에 DETERMINISTIC을 붙였다. "같은 상품이면 한 번만 계산된다고 해서요."
개발자가 SQL*Plus에서 ARRAYSIZE 5000으로 시험했을 때는 함수 본문 실행이 14,697번에서 4,412번으로 줄었다. 그런데 관리자 화면(Java, JDBC)에서 내려받으면 그대로다.
orders: 34,908행 · 193블록 · order_date DATE(시분초 있음) · PK만 · 2024년 주문 6,982건order_items: 73,498행 · 290블록 · PK만 · 2024년 주문의 상품 14,697행 · 그해 팔린 상품 271종products: 280행 · 8블록 · PK(product_id) · category_idcategories: 53행 · 4블록 · PK(category_id) · nameCREATE OR REPLACE FUNCTION fn_category_name(p_product_id NUMBER) RETURN VARCHAR2 DETERMINISTIC IS
v_name categories.name%TYPE;
BEGIN
SELECT c.name INTO v_name
FROM products p, categories c
WHERE p.product_id = p_product_id
AND c.category_id = p.category_id;
RETURN v_name;
END;
/
SELECT o.order_id, o.order_date, oi.product_id, oi.quantity, oi.unit_price,
fn_category_name(oi.product_id) AS category_name
FROM orders o, order_items oi
WHERE o.order_date >= DATE '2024-01-01'
AND o.order_date < DATE '2025-01-01'
AND oi.order_id = o.order_id;
[관리자 화면에서 내려받을 때: DISPLAY_CURSOR (ALLSTATS LAST)]
-------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Used-Mem |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14697 |00:00:00.69 | 1953 | |
|* 1 | HASH JOIN | | 1 | 14620 | 14697 |00:00:00.69 | 1953 | 1199K (0)|
|* 2 | TABLE ACCESS FULL| ORDERS | 1 | 6982 | 6982 |00:00:00.01 | 193 | |
| 3 | TABLE ACCESS FULL| ORDER_ITEMS | 1 | 73498 | 73498 |00:00:00.03 | 1760 | |
-------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OI"."ORDER_ID"="O"."ORDER_ID")
2 - filter(("O"."ORDER_DATE">=TO_DATE(' 2024-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"O"."ORDER_DATE"<TO_DATE(' 2025-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
(ORDER_ITEMS 1,760 = 290블록 + 페치 1,470번마다 다시 잡은 블록)
[함수 본문 실행 수: 함수 안 SELECT의 V$SQL.EXECUTIONS 증가분]
받는 쪽 페치 크기 페치 수 DETERMINISTIC 전 DETERMINISTIC 후 경과(후)
관리자 화면 (JDBC) 10 1,470 14,697 14,453 0.69 초
SQL*Plus 시험 (ARRAYSIZE 5000) 5,000 3 14,697 4,412 0.27 초
DETERMINISTIC은 어떻게 할지도 쓰시오.