Scalar Subquery Cache·Result Cache·DETERMINISTIC: 재사용과 정확성
반복 계산을 줄이는 Scalar Subquery Cache, SQL·PL/SQL Result Cache와 DETERMINISTIC의 보장 범위를 비교합니다.
핵심 요약
반복 계산을 줄이는 기능마다 Cache 범위와 정확성 보장이 다릅니다. 다음 네 가지를 분리해서 이해해야 합니다.
| 기능 | 재사용 범위 | 저장 대상 | 핵심 판단 |
|---|---|---|---|
| Scalar Subquery 실행 중 재사용 | 한 SQL 실행 내부 | 상관 Key에 대한 스칼라 결과 | 반복 Key·충돌·실제 Starts |
| SQL Result Cache | 여러 실행·Session | SQL Query Block의 결과 집합 | 작은 결과·낮은 변경률·Invalidation |
| PL/SQL Function Result Cache | 여러 실행·Session | 함수 인수별 반환값 | 함수 의존 데이터·인수 다양성 |
DETERMINISTIC | Cache 범위를 정의하지 않음 | 같은 입력에 같은 결과라는 함수 속성 선언 | 정확성 계약·부작용 금지 |
DETERMINISTIC은 함수의 의미적 속성을 선언하고, Result Cache는 계산 결과를 저장합니다. Result Cache를 사용해도 Eligibility·입력값·무효화·Memory·Blocklist·실행 횟수 조건에 따라 실제 재사용 범위가 달라집니다.
재사용 대상은 무엇인가?
→ 상관 Key별 Scalar 값
→ SQL Query 결과
→ 함수 인수별 반환값
재사용 범위는 어디까지인가?
→ 현재 Statement
→ 여러 실행·Session
정확성을 누가 보장하는가?
→ Database Dependency 추적
→ 개발자의 DETERMINISTIC·Session State 계약
이 이론의 범위
SQLP
SQL 고급 활용 및 튜닝 → 스칼라 서브쿼리범위에서 Statement 내부 재사용, Server Result Cache, PL/SQL Function Result Cache, DETERMINISTIC, Invalidation·Bypass·진단 View를 다룹니다.
학습 목표
이 이론을 학습한 뒤에는 다음을 설명할 수 있어야 합니다.
- Scalar Subquery 실행 중 재사용과 Server Result Cache의 범위를 구분한다.
- SQL Result Cache와 PL/SQL Function Result Cache의 저장 대상을 비교한다.
DETERMINISTIC의 의미와 Result Cache와의 차이를 설명한다.- 반복 Key 수와 NDV가 Scalar Subquery 재사용 효과에 미치는 영향을 판단한다.
- 의존 Object 변경과 Session State가 Cache 정확성에 미치는 영향을 설명한다.
- Result Cache가 유리한 Query와 불리한 Query를 구분한다.
RESULT_CACHE_MODE,RESULT_CACHE_INTEGRITY, Cache 활성 상태를 구분한다.- Function Result Cache의 실행 Threshold와 Cache Hit 인수 비교 규칙을 설명한다.
- DML 중 Result Cache Bypass와 Commit 후 Invalidation을 구분한다.
- 실행계획과 Dynamic Performance View로 재사용 효과를 검증한다.
1. 먼저 구분해야 할 네 가지 개념
Scalar Subquery 실행 중 재사용
상관 스칼라 서브쿼리의 입력 Key가 반복될 때 Oracle은 한 Statement 실행 안에서 이미 계산한 결과를 내부적으로 재사용할 수 있습니다.
SELECT o.order_id,
(SELECT c.customer_name
FROM customer c
WHERE c.customer_id = o.customer_id) AS customer_name
FROM orders o;
ORDERS의 여러 행이 같은 CUSTOMER_ID를 가지면 동일한 고객명 Lookup 결과를 다시 사용할 가능성이 있습니다.
이 재사용은 다음 특성을 가집니다.
범위
→ 현재 SQL 실행 내부
Key
→ 상관 Column 값의 조합
효과
→ Subquery 또는 함수의 실제 실행 횟수 감소 가능
보장
→ 모든 반복 Key가 반드시 한 번만 계산되는 것은 아님
Cache 용량, Hash 충돌, Key 분포, Optimizer 변환에 따라 효과가 달라질 수 있으므로 고정된 Cache 크기나 적중률을 암기하지 않고 실제 통계로 확인합니다.
SQL Result Cache
SQL Query의 결과 행 집합을 Server Result Cache에 저장하고 동일한 Query가 다시 실행될 때 재사용하는 기능입니다.
SELECT /*+ RESULT_CACHE */
region_id,
SUM(order_amount) AS total_amount
FROM orders
GROUP BY region_id;
Cache Hit가 발생하면 Base Table을 다시 읽고 집계하는 작업 대신 저장된 결과를 사용할 수 있습니다.
PL/SQL Function Result Cache
함수의 입력 인수와 반환값을 Result Cache에 저장합니다.
CREATE OR REPLACE FUNCTION get_exchange_rate(
p_currency_code VARCHAR2
) RETURN NUMBER
RESULT_CACHE
IS
l_rate NUMBER;
BEGIN
SELECT exchange_rate
INTO l_rate
FROM exchange_rate_master
WHERE currency_code = p_currency_code;
RETURN l_rate;
END;
/
동일한 인수로 함수를 다시 호출할 때 유효한 Cache Entry가 있으면 함수 본문 실행을 줄일 수 있습니다.
DETERMINISTIC
함수가 같은 입력값에 대해 항상 같은 결과를 반환하며 부작용을 만들지 않는다는 개발자의 선언입니다.
CREATE OR REPLACE FUNCTION normalize_code(
p_code VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN UPPER(TRIM(p_code));
END;
/
이 선언은 함수의 의미적 속성을 나타냅니다. 별도의 Result Cache 저장 공간이나 Cache 생명주기를 정의하지 않습니다.
2. Scalar Subquery 재사용의 작동 조건
다음 데이터가 있다고 가정합니다.
ORDERS 1,000,000행
CUSTOMER_ID NDV 1,000
주문은 백만 건이지만 고객은 천 명이므로 같은 고객번호가 반복됩니다.
Outer 행 수 = 1,000,000
서로 다른 상관 Key = 1,000
이 경우 고객명 Lookup 결과를 실행 중 재사용할 기회가 많습니다.
반대로 다음과 같다면 재사용 가능성이 낮아집니다.
ORDERS 1,000,000행
CUSTOMER_ID NDV 950,000
대부분의 행이 서로 다른 Key를 사용하므로 Cache Entry가 재사용되기 전에 새로운 Key가 계속 들어올 수 있습니다.
재사용 효과에 영향을 주는 요소
- 바깥 Row Source의 행 수
- 상관 Key의 NDV
- 같은 Key가 나타나는 순서와 집중도
- Cache Entry 충돌
- Subquery 한 번의 비용
- Optimizer의 Unnesting 여부
- 일부 Fetch인지 전체 Fetch인지
- Parallel Execution과 실행 구조
정렬로 Cache Hit를 높이는 접근
같은 상관 Key를 모아 처리하면 재사용 가능성이 높아질 수 있지만, 이를 위해 추가 Sort가 필요하면 전체 비용이 더 커질 수 있습니다.
Key 정렬 비용
↕
Subquery 반복 감소 이득
Cache Hit만 높이기 위해 불필요한 ORDER BY를 추가하지 않고, Sort Workarea·TEMP와 전체 응답시간을 함께 비교합니다.
3. Scalar Subquery Cache를 직접 설정하는가
Scalar Subquery의 실행 중 재사용은 일반 SQL 문법으로 크기나 교체 정책을 직접 설정하는 사용자 관리 Cache와 구분됩니다.
다음과 같은 접근을 피합니다.
Cache Bucket 수를 고정 상수로 암기
숨은 Parameter로 Cache 크기 변경
모든 반복 Key는 반드시 한 번만 실행된다고 가정
검증은 실제 Cursor 통계를 이용합니다.
SELECT /*+ GATHER_PLAN_STATISTICS */
o.order_id,
(SELECT c.customer_name
FROM customer c
WHERE c.customer_id = o.customer_id) AS customer_name
FROM orders o;
SELECT *
FROM TABLE(
DBMS_XPLAN.DISPLAY_CURSOR(
NULL,
NULL,
'ALLSTATS LAST +PREDICATE +ALIAS +NOTE'
)
);
다음 값을 비교합니다.
Outer A-Rows
상관 Key NDV
Subquery Starts
Inner A-Rows
Inner Buffers
전체 A-Time
예시 해석
Outer A-Rows = 100,000
상관 Key NDV = 500
Subquery Starts = 650
실제 Starts가 Outer 행 수보다 크게 작다면 실행 중 재사용이나 다른 최적화가 영향을 주었을 가능성을 검토할 수 있습니다.
Outer A-Rows = 100,000
Subquery Starts = 100,000
반복 실행이 거의 그대로 발생했다면 Join·사전 집계·LATERAL 대안과 비교합니다.
실행계획의 Starts는 Row Source 시작 횟수이므로 내부 Cache Hit 전체를 단독으로 설명하지는 못합니다. 다음을 함께 사용합니다.
Outer A-Rows
상관 Key NDV
Subquery Starts
Inner Buffers·A-Time
SQL Trace
함수 호출 Counter
전체 Fetch 범위
또한 Scalar Subquery 실행 중 재사용은 Server Result Cache의 V$RESULT_CACHE_OBJECTS에 사용자가 관리하는 Entry로 나타나는 기능과 구분합니다. Statement 종료 후 여러 Session이 공유하는 Cache라고 가정하지 않습니다.
4. SQL Result Cache의 범위
Server Result Cache는 Shared Pool 내부의 Result Cache Memory를 사용하며, SQL Query 결과를 여러 실행과 Session이 재사용할 수 있습니다.
Session A가 Query 실행
→ Query 결과 생성
→ Result Cache 저장
Session B가 같은 결과를 요청
→ 유효한 Cache Entry 확인
→ 저장된 결과 재사용 가능
적합한 Query
- 동일한 Query가 자주 반복됨
- 많은 Base Row를 읽지만 결과는 작음
- 집계·정렬 비용이 큼
- 원본 데이터 변경이 드묾
- Bind 값 조합의 종류가 제한적임
- 여러 Session이 같은 결과를 반복 요청함
예를 들어 기준정보나 일별 마감 집계처럼 데이터 변경은 적고 조회는 많은 경우를 검토할 수 있습니다.
불리한 Query
- 원본 Table에 DML이 매우 자주 발생함
- 결과 집합이 큼
- Bind 값 조합이 매우 다양함
- Query가 한 번 또는 드물게 실행됨
- Session별 상태나 현재 시간에 따라 결과가 달라짐
- Cache 무효화와 재생성이 반복됨
의존 Object 변경
Cache 결과를 만든 Table이나 View의 데이터가 Commit된 변경으로 수정되면 관련 결과가 무효화될 수 있습니다.
Query 결과 Cache
→ 의존 Table 변경·Commit
→ 관련 Cache Entry Invalidation
→ 다음 실행에서 재계산
DML이 빈번하면 Hit보다 Invalidation과 재생성 비용이 커질 수 있습니다.
4.1 Server Result Cache의 활성 상태와 정책
Server Result Cache는 Shared Pool 내부의 SQL Query Result Cache와 PL/SQL Function Result Cache가 공유하는 Memory 영역입니다.
주요 설정은 다음과 같습니다.
| 항목 | 역할 |
|---|---|
RESULT_CACHE_MODE | SQL Query 결과를 Manual Hint 중심으로 사용할지, 가능한 Query에 Force할지 결정 |
RESULT_CACHE_MAX_SIZE | Server Result Cache Memory 최대 크기 |
RESULT_CACHE_INTEGRITY | Result Cache 적격성 판단에서 결정성 무결성 정책 |
RESULT_CACHE_MAX_RESULT | 단일 결과가 Memory Cache에서 차지할 수 있는 비율 관련 설정 |
RESULT_CACHE_EXECUTION_THRESHOLD | 함수와 특정 인수 조합이 Cache 대상이 되기 전 관찰 횟수 |
Cache 활성 여부는 Parameter 값만 보지 않고 다음처럼 확인할 수 있습니다.
SELECT DBMS_RESULT_CACHE.STATUS()
FROM dual;
Instance 시작 시 Result Cache가 비활성화된 경우, 일부 Parameter 값을 동적으로 바꿔도 재시작 전 실제 Cache 상태와 표시값이 다를 수 있으므로 DBMS_RESULT_CACHE.STATUS()를 확인합니다.
RESULT_CACHE_INTEGRITY 정책과 Query의 비결정적 요소에 따라 Hint가 있어도 Cache 적격성이 달라질 수 있습니다.
5. SQL Result Cache 사용 방법
대표적인 방법은 Query Block에 RESULT_CACHE Hint를 지정하는 것입니다.
SELECT /*+ RESULT_CACHE */
product_category,
SUM(sales_amount) AS total_amount
FROM sales
WHERE sales_date >= DATE '2026-01-01'
GROUP BY product_category;
Cache 사용을 제외하려면 다음 Hint를 사용할 수 있습니다.
SELECT /*+ NO_RESULT_CACHE */
...
FROM ...;
Result Cache Hint는 지정된 Query Block의 결과에 적용됩니다. Inline View나 WITH Query에 지정할 때는 어느 Query Block의 결과를 재사용하려는지 확인해야 합니다.
최근 버전에서는 Hint Scope와 Temporary Result 사용 정책이 확장될 수 있으므로 운영 Version의 Hint 문법과 설정을 확인합니다. 결과가 Memory의 단일 결과 제한보다 큰 경우 Temp 유형 Result Cache Object가 Temporary Tablespace를 사용할 수 있으므로 “Result Cache는 항상 Memory-only”라고 단정하지 않습니다.
Hint가 있다고 반드시 Cache되는 것은 아니다
다음 조건에 따라 Cache Entry가 생성되거나 재사용되지 않을 수 있습니다.
- Query가 Result Cache 제한 사항에 해당
- Result Cache Memory 부족
- 결과가 너무 큼
- 의존 Object 상태 변경
- 입력 Bind 값이 기존 Entry와 다름
- Database 설정과 Hint 적용 범위
- Cache Blocklist 또는 내부 정책
따라서 Hint 존재 여부보다 실제 실행계획과 Result Cache View를 확인합니다.
6. PL/SQL Function Result Cache
PL/SQL Function Result Cache는 다음 조합을 Key처럼 사용합니다.
함수 식별 정보
+ 입력 인수 값
→ 반환값
예를 들어 다음 호출은 서로 다른 Cache Entry 후보입니다.
get_exchange_rate('USD')
get_exchange_rate('JPY')
get_exchange_rate('EUR')
Cache 생성 Threshold
Oracle AI Database 26ai의 PL/SQL Function Result Cache는 최근 호출 이력을 이용해 함수와 특정 인수 조합이 일정 횟수 관찰된 뒤 Cache할 수 있습니다.
RESULT_CACHE_EXECUTION_THRESHOLD = 2 예시
첫 호출
→ 함수 계산, 아직 Cache하지 않을 수 있음
둘째 호출
→ 함수 계산 후 Cache Entry 생성 후보
셋째 호출
→ 유효한 Entry가 있으면 재사용
따라서 첫 호출부터 반드시 Cache Hit가 발생한다고 가정하지 않습니다. Threshold는 운영 설정을 확인합니다.
Cache Hit의 인수 비교
Function Result Cache의 인수 비교는 PL/SQL의 일반 = 비교와 완전히 같지 않습니다.
NULL 인수
→ Cache Hit 비교에서는 NULL과 NULL이 같은 Key로 취급
Non-NULL Scalar
→ 값의 표현이 동일한지 엄격하게 비교
→ CHAR 'AA'와 'AA '가 별도 Entry가 될 수 있음
인수 정규화 방식과 데이터 타입이 Cache Entry 수에 영향을 줄 수 있습니다.
적합한 함수
- 자주 호출됨
- 계산 또는 Lookup 비용이 큼
- 반환값이 작음
- 인수 종류가 제한적임
- 의존 데이터가 드물게 변경됨
- Session State에 의존하지 않음
의존 데이터 추적
Result-Cached Function이 실행 중 조회한 Table과 View를 Database가 추적할 수 있습니다. 해당 데이터에 Commit된 변경이 발생하면 관련 Cache 결과가 무효화됩니다.
함수 결과 Cache
→ 함수가 참조한 기준 Table 변경
→ Cache Entry Invalidation
→ 다음 호출에서 함수 재실행
주의할 외부 상태
다음 값에 결과가 의존하면 Cache 정확성을 별도로 검토해야 합니다.
SYSDATE,SYSTIMESTAMP- Sequence
- Package Global Variable
SYS_CONTEXT- Session NLS 설정
- 애플리케이션 Context
- 외부 File·Network 상태
- Commit되지 않은 Session별 상태
Database가 추적하지 못하는 상태가 반환값에 영향을 주면 유효하지 않은 결과가 재사용될 수 있습니다.
DML 중 Cache Bypass
한 Session이 Result-Cached Function이 의존하는 Table에 DML을 수행 중이면 해당 Session은 Transaction이 Commit 또는 Rollback될 때까지 Cache를 우회할 수 있습니다.
Session A
→ 기준 Table UPDATE
→ 자신의 미Commit 변경을 보아야 함
→ 관련 Function Result Cache Bypass
→ 함수 직접 계산
→ 계산 결과도 Cache에 저장하지 않음
이 동작은 Session 자신의 미Commit 변경을 다른 Session의 공유 Cache 결과와 혼동하지 않게 합니다.
Commit
→ 의존 Cache Entry Invalidation 가능
Rollback
→ 공유 Cache의 기존 Committed 결과 사용 재개 가능
Bypass와 Invalidation은 서로 다른 시점과 목적의 동작입니다.
7. DETERMINISTIC의 정확한 의미
DETERMINISTIC 함수는 다음 규칙을 만족해야 합니다.
같은 입력 인수
→ 같은 반환값
호출 과정
→ 외부 상태를 변경하는 부작용 없음
→ 처리되지 않은 예외를 발생시키지 않음
예를 들어 문자열을 정규화하는 순수 함수는 적합할 수 있습니다.
CREATE OR REPLACE FUNCTION canonical_email(
p_email VARCHAR2
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN LOWER(TRIM(p_email));
END;
/
다음 함수는 현재 시간에 따라 결과가 바뀌므로 같은 입력에 같은 결과를 보장하지 못합니다.
CREATE OR REPLACE FUNCTION make_token(
p_id NUMBER
) RETURN VARCHAR2
DETERMINISTIC
IS
BEGIN
RETURN p_id || ':' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
END;
/
선언을 Database가 완전히 검증하지 않는다
DETERMINISTIC은 개발자가 의미적 규칙을 지킨다는 선언입니다. 함수 구현이 규칙을 위반해도 Compiler·SQL Engine·PL/SQL Engine이 문제를 진단하지 않을 수 있으며, Oracle 공식 의미상 Invocation 결과와 호출자에 미치는 영향이 정의되지 않은 상태가 될 수 있습니다.
따라서 단순히 성능을 위해 거짓으로 DETERMINISTIC을 선언하면 안 됩니다.
사용되는 대표 위치
PL/SQL 함수를 다음 구조에서 사용하려면 DETERMINISTIC 속성이 중요합니다.
- Function-Based Index
- PL/SQL 함수를 사용하는 Virtual Column
- Query Rewrite 또는 Fast Refresh와 관련된 Materialized View 표현식
함수 구현이 변경되면 종속된 Function-Based Index나 Materialized View는 자동으로 새 함수 의미에 맞게 재작성된다고 가정하지 않습니다. 관련 Function-Based Index와 Materialized View를 수동으로 Rebuild·Refresh하고 결과를 재검증합니다.
8. DETERMINISTIC과 RESULT_CACHE 비교
| 항목 | DETERMINISTIC | RESULT_CACHE |
|---|---|---|
| 핵심 목적 | 함수의 의미적 성질 선언 | 함수 결과를 Cache에 저장 |
| 저장 공간 | 별도 Cache를 정의하지 않음 | Server Result Cache 사용 |
| 같은 입력 | 같은 결과를 반환해야 함 | 같은 인수 Entry를 재사용 가능 |
| 의존 데이터 변경 | 자동 Cache Invalidation 개념이 핵심이 아님 | 추적된 의존 Object 변경 시 무효화 |
| 정확성 책임 | 개발자 선언의 정확성이 핵심 | Cache 대상·Dependency·추적되지 않는 상태 검토 |
| 첫 호출 | 별도 Cache 생성 규칙을 정의하지 않음 | Threshold·Memory·Eligibility에 따라 함수 본문 실행 가능 |
| DML 중 | Cache Bypass 개념과 별개 | 의존 Table DML Session은 Cache를 우회할 수 있음 |
| 주요 사용 | FBI·Virtual Column·Query Rewrite 등 | 반복 Function 호출 비용 감소 |
DETERMINISTIC 함수도 매 호출이 Result Cache에서 반환된다고 보장되지 않습니다.
RESULT_CACHE 함수는 Session State에 따라 달라지는 값을 저장할 때 정확성 위험이 생길 수 있습니다.
두 속성은 서로 대체 관계가 아니라 목적이 다른 기능입니다.
9. 스칼라 서브쿼리와 PL/SQL 함수 호출
SQL에서 PL/SQL 함수를 행마다 호출하면 다음 비용이 생길 수 있습니다.
SQL Engine
→ PL/SQL Function 호출
→ 함수 내부 SQL 실행
→ 결과 반환
Outer 행이 많으면 Engine 전환과 함수 내부 SQL이 반복됩니다.
SELECT o.order_id,
get_customer_grade(o.customer_id) AS customer_grade
FROM orders o;
함수 호출을 스칼라 서브쿼리 안에 배치하면 반복 Key 결과의 실행 중 재사용 기회를 얻는 경우가 있지만, 이는 보장된 일반 해법으로 사용하지 않습니다.
SELECT o.order_id,
(SELECT get_customer_grade(o.customer_id)
FROM dual) AS customer_grade
FROM orders o;
다음 대안을 우선 비교합니다.
함수 내부 SQL을 Join으로 전개
기준 Table을 직접 Join
사전 집계
PL/SQL RESULT_CACHE
Statement 내부 Scalar 재사용
정확한 결과 의미와 전체 실행 비용을 실측한 뒤 선택합니다.
SQL에서 호출되는 PL/SQL 함수는 SQL Engine과 PL/SQL Engine 사이의 전환 비용이 누적될 수 있습니다. PRAGMA UDF 등 호출 오버헤드 완화 기능이 있더라도 함수 내부의 반복 SQL과 데이터 접근량을 자동 제거하는 것은 아니므로 Join·집합 처리 대안과 비교합니다.
10. Result Cache 진단 도구
Cache Object 확인
SELECT type,
status,
name,
namespace,
block_count,
scan_count
FROM v$result_cache_objects
ORDER BY type, name;
주요 해석은 다음과 같습니다.
| 항목 | 의미 |
|---|---|
TYPE | Result·Dependency·Temp Object 유형 |
STATUS | Cache Object 상태 |
NAMESPACE | SQL·PLSQL·KEY VECTOR 등 구분 |
BLOCK_COUNT | 사용한 Cache Block |
SCAN_COUNT | 재사용된 횟수를 판단하는 참고값 |
Database 버전에 따라 View Column이 달라질 수 있으므로 현재 Version의 Data Dictionary를 확인합니다.
STATUS는 New, Published, Bypass, Expired, Invalid 등 Cache Object의 현재 상태를 보여 줄 수 있습니다. SCAN_COUNT가 0인 Result가 대량으로 누적되면 Entry를 만들었지만 재사용하지 못한 패턴인지 점검합니다.
전체 Statistics 확인
SELECT id,
name,
value
FROM v$result_cache_statistics
ORDER BY id;
Memory Report
SET SERVEROUTPUT ON
BEGIN
DBMS_RESULT_CACHE.MEMORY_REPORT;
END;
/
실행계획 확인
Result Cache를 사용하는 Query는 실행계획에서 Result Cache 관련 Row Source나 Note를 확인할 수 있습니다. 다음도 함께 비교합니다.
첫 실행과 두 번째 실행의 Buffers·A-Time
Cache Hit 여부
의존 Object 변경 후 재실행
서로 다른 Bind 값의 Entry 수
Cache Object의 크기와 재사용 횟수
11. Cache 사용 전후 검증 시나리오
1단계: 기준 실행
Cache를 사용하지 않은 실행
→ Elapsed Time
→ CPU
→ Buffers
→ Reads
→ 반환 Row 수
2단계: 첫 Cache 생성 실행
Query 실제 수행
→ 결과 생성
→ Cache Entry 저장 가능
첫 실행은 Cache 생성 비용까지 포함하므로 Hit 실행과 분리합니다.
3단계: 동일 입력 반복 실행
동일 SQL 또는 함수
동일 Bind·인수
동일 Session 상태
의존 데이터 변경 없음
Function Result Cache는 RESULT_CACHE_EXECUTION_THRESHOLD 때문에 두 번째 실행까지 함수 본문이 실행되고 이후에 Hit가 나타날 수 있으므로 최소 3회 이상 반복해 관찰합니다.
4단계: 다른 입력
Bind 값이나 함수 인수를 바꾸어 Entry가 분리되는지 확인합니다.
5단계: 의존 데이터 변경과 Transaction
DML 전 Hit 실행
→ 같은 Session에서 의존 Table DML
→ Commit 전 Cache Bypass·자기 변경 가시성 확인
→ Commit
→ 관련 Entry Invalidation 확인
→ 다음 실행 재계산
Rollback 경로도 별도로 확인합니다.
6단계: 동시 실행
여러 Session에서 Hit Rate뿐 아니라 Shared Pool 경합과 전체 처리량을 확인합니다.
12. Result Cache가 유리한지 판단하는 공식
정확한 비용은 환경마다 다르지만 다음 구조로 생각할 수 있습니다.
Cache 이득
≈ 반복 실행 횟수 × 원래 계산 비용
- Cache Lookup 비용
- Cache 생성 비용
- Invalidation·재생성 비용
- Result Cache Memory·TEMP 비용
- Threshold 도달 전 실행 비용
유리한 패턴
계산 비용 큼
반복 횟수 많음
결과 작음
입력 종류 적음
원본 변경 적음
불리한 패턴
계산 비용 작음
반복 횟수 적음
결과 큼
입력 종류 많음
원본 변경 많음
Session별 결과 차이 큼
Cache Hit Ratio만 높고 원래 Query가 매우 가볍다면 전체 성능 개선은 작을 수 있습니다. 반대로 Hit Ratio가 완벽하지 않아도 매우 비싼 Query를 반복해서 피하면 효과가 클 수 있습니다.
혼동하기 쉬운 판단
| 혼동하기 쉬운 판단 | 정확한 기준 |
|---|---|
| Scalar Subquery Cache는 모든 Session이 공유한다 | 현재 Statement 실행 내부의 재사용으로 이해한다 |
| 반복 Key는 항상 한 번만 계산된다 | Cache 충돌·Key 분포·변환에 따라 실제 Starts가 달라진다 |
RESULT_CACHE Hint가 있으면 반드시 Cache Hit가 난다 | Eligibility·Memory·Bind·Invalidation·설정을 확인한다 |
| Result Cache는 DML이 많을수록 최신 결과를 빠르게 준다 | DML이 많으면 Invalidation과 재생성이 반복될 수 있다 |
DETERMINISTIC은 자동 Result Cache다 | 같은 입력에 같은 결과를 보장한다는 함수 속성 선언이다 |
DETERMINISTIC 위반은 항상 오류로 발견된다 | Compile·실행에서 진단되지 않고 잘못된 결과가 생길 수 있다 |
| PL/SQL Result Cache는 모든 외부 상태를 추적한다 | 추적되지 않는 Session·시간·외부 상태를 개발자가 검토해야 한다 |
| Cache Hit Ratio만 높으면 성공이다 | 원래 계산 비용·Memory·Invalidation·전체 처리량을 함께 본다 |
| Function Result Cache는 첫 호출부터 저장·Hit | Execution Threshold에 따라 여러 호출 후 Cache될 수 있다 |
Result Cache 인수 비교는 PL/SQL =와 완전히 같다 | NULL·CHAR 등 Cache Key 비교 규칙이 더 엄격할 수 있다 |
| Result Cache는 항상 Shared Pool Memory만 사용 | 큰 결과는 Version·설정에 따라 Temp Object가 될 수 있다 |
| DML 중에도 항상 기존 Function Cache를 읽는다 | 자신의 미Commit 변경을 위해 Cache Bypass가 발생할 수 있다 |
| DETERMINISTIC 함수는 예외를 발생시켜도 된다 | 처리되지 않은 예외도 의미 규칙을 위반한다 |
| 함수 수정 후 FBI가 자동으로 새 의미를 반영 | 종속 FBI·MV를 수동 Rebuild·Refresh하고 검증한다 |
핵심 판단 순서
반복되는 것은 Query 결과인가, 함수 결과인가, 상관 Key 결과인가?
→ 필요한 재사용 범위는 한 실행인가, 여러 실행·Session인가?
→ Cache가 실제 ENABLED인가?
→ RESULT_CACHE_MODE·INTEGRITY·EXECUTION_THRESHOLD는 무엇인가?
→ 입력 Key·Bind·함수 인수의 NDV와 표현은 얼마인가?
→ 결과 크기와 원래 계산 비용은 얼마인가?
→ Memory 결과인가 Temp Object 가능성이 있는가?
→ 의존 데이터는 얼마나 자주 변경되는가?
→ DML 중 Bypass와 Commit 후 Invalidation은 어떻게 발생하는가?
→ Session State·시간·Sequence·외부 상태에 따라 결과가 달라지는가?
→ DETERMINISTIC 의미 규칙을 실제로 만족하는가?
→ 실제 Starts·Buffers·Cache Object·Statistics로 효과를 검증했는가?
개념 확인 문제
문제를 누르면 바로 아래에서 정답과 해설을 확인할 수 있습니다.
01Scalar Subquery 실행 중 재사용과 SQL Result Cache의 가장 큰 범위 차이는 무엇인가?
Scalar Subquery 실행 중 재사용은 현재 SQL Statement 내부의 반복 상관 Key 결과를 대상으로 하고, SQL Result Cache는 Query 결과를 여러 실행·Session에서 재사용할 수 있습니다.
02상관 Key의 NDV가 매우 클 때 Scalar Subquery 재사용 효과가 작아질 수 있는 이유는 무엇인가?
상관 Key NDV가 Outer Row 수에 가까우면 이미 계산한 Key가 다시 나타날 기회가 적고 Cache 충돌·교체 가능성이 커집니다.
03SQL Result Cache에 적합한 Query의 대표적인 특징 세 가지는 무엇인가?
많은 Base Row를 읽지만 결과는 작고, 반복 실행이 많고, Bind 종류가 제한적이며, 의존 데이터 변경이 드문 Query가 SQL Result Cache 후보입니다.
04의존 Table에 Commit된 변경이 발생하면 SQL·PL/SQL Result Cache에 어떤 일이 생길 수 있는가?
의존 Object의 Commit 변경은 관련 SQL·PL/SQL Result Cache Entry를 Invalid 상태로 만들 수 있고 다음 실행에서 재계산하게 합니다.
05PL/SQL Function Result Cache는 무엇을 기준으로 결과를 구분하는가?
PL/SQL Function Result Cache는 함수 식별 정보와 입력 인수 값의 조합으로 Entry를 구분합니다. NULL·CHAR 등 Cache Hit 비교는 일반 PL/SQL =와 다를 수 있습니다.
06DETERMINISTIC 함수가 만족해야 하는 핵심 규칙 두 가지는 무엇인가?
DETERMINISTIC 함수는 같은 인수에 같은 값을 반환하고, 부작용이 없으며, 처리되지 않은 예외를 발생시키지 않아야 합니다.
07DETERMINISTIC을 잘못 선언했을 때 특히 위험한 이유는 무엇인가?
DETERMINISTIC은 Database가 완전히 검증하는 보증이 아니라 개발자의 Assertion입니다. 위반하면 오류 없이 잘못된 값이나 정의되지 않은 결과가 생길 수 있습니다.
08SYSDATE, Sequence, Package Variable에 의존하는 함수가 Cache에 부적합할 수 있는 이유는 무엇인가?
SYSDATE·Sequence·Package Variable·SYS_CONTEXT·NLS·외부 상태는 같은 명시적 인수에서도 결과를 바꿀 수 있고 Dependency 추적 대상이 아닐 수 있습니다.
09Result Cache 효과를 검증할 때 첫 실행과 두 번째 실행을 분리해야 하는 이유는 무엇인가?
첫 실행은 계산 비용과 Cache 생성 비용을 포함하고, Function Result Cache는 Execution Threshold 때문에 여러 번 실행된 뒤 Hit가 나타날 수 있으므로 생성 실행과 Hit 실행을 분리해야 합니다.
10Scalar Subquery·SQL Result Cache·PL/SQL Result Cache·DETERMINISTIC 중 어떤 기능을 선택할지 판단하는 첫 질문은 무엇인가?
먼저 재사용하려는 대상과 범위를 확정합니다. Statement 내부 상관 Key인지, SQL 결과인지, 함수 인수별 결과인지에 따라 Scalar 재사용·SQL Result Cache·Function Result Cache를 선택하고 DETERMINISTIC은 별도의 정확성 선언으로 판단합니다.