<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://dbstudy.co.kr/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oracle</id>
	<title>DB스터디 - 사용자 기여 [ko]</title>
	<link rel="self" type="application/atom+xml" href="https://dbstudy.co.kr/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oracle"/>
	<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Oracle"/>
	<updated>2026-09-21T23:43:17Z</updated>
	<subtitle>사용자 기여</subtitle>
	<generator>MediaWiki 1.39.10</generator>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Enq:hw-contention&amp;diff=1915</id>
		<title>Enq:hw-contention</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Enq:hw-contention&amp;diff=1915"/>
		<updated>2026-09-21T23:34:08Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* HW(High Water Mark) Enqueue가 무엇인가? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== enq: HW - Contention ==&lt;br /&gt;
* LOB Segment 이슈와 밀접하게 연결되는 대기 이벤트입니다. &lt;br /&gt;
* 특히 동시성 높은 환경에서 LOB 컬럼에 INSERT가 몰릴 때 자주 발생하는 이슈&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== HW(High Water Mark) Enqueue가 무엇인가?  ===&lt;br /&gt;
* 개념: 세그먼트(Table, Index, LOB Segment 등)가 &amp;quot;새로운 블록 영역으로 확장&amp;quot; 될 때 걸리는 직렬화 락(Lock)&lt;br /&gt;
&lt;br /&gt;
* HWM(High Water Mark)란?&lt;br /&gt;
: :이 세그먼트가 지금까지 한 번이라도 사용한 적 있는 블록의 최대 경계선&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
[세그먼트 내부 이미지]&lt;br /&gt;
┌────────┬────────┬────────┬────────┬─────────────┐&lt;br /&gt;
│ 사용중 │ 사용중 │ 사용중  │ 미사용  │   미사용    │&lt;br /&gt;
│ Block1 │ Block2 │ Block3 │ Block4 │   Block5    │&lt;br /&gt;
└────────┴────────┴────────┴────────┴─────────────┘&lt;br /&gt;
                            ▲&lt;br /&gt;
                           HWM (여기까지가 &amp;quot;사용해본 적 있는&amp;quot; 경계)&lt;br /&gt;
&lt;br /&gt;
→ HWM을 넘어 Block4, Block5로 최초 진입(확장)하려면 &lt;br /&gt;
  &amp;quot;누군가 한 명만&amp;quot; HWM을 이동시키는 작업을 해야 함&lt;br /&gt;
→ 그 &amp;quot;한 명만 하도록 강제&amp;quot;하는 직렬화 장치가 바로 enq: HW 이다&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*핵심: HW 이동 자체는 원자적(Atomic)이어야 하므로, 여러 세션이 동시에 HWM을 넘기려고 시도하면 한 세션만 실제로 이동시키고 나머지는 대기합니다. &lt;br /&gt;
이 대기가 `enq: HW - contention`입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 어떤 상황에서 자주 발생하는가? ===&lt;br /&gt;
&lt;br /&gt;
# 발생 빈발 시나리오 TOP 3&lt;br /&gt;
#:&amp;lt;source&amp;gt;&lt;br /&gt;
1순위: LOB Segment 동시 INSERT (가장 빈번)&lt;br /&gt;
:   → 여러 세션이 동시에 CLOB/BLOB 컬럼에 대량 데이터를 INSERT&lt;br /&gt;
:   → 특히 NOCACHE + 병렬 세션 조합에서 극심&lt;br /&gt;
&lt;br /&gt;
2순위: 병렬 Direct-Path INSERT (APPEND Hint)&lt;br /&gt;
 :  → 여러 병렬 슬레이브가 동시에 같은 테이블 뒤쪽에 데이터 적재&lt;br /&gt;
&lt;br /&gt;
3순위: 시퀀스 없는 대량 동시 INSERT (일반 Heap 테이블)&lt;br /&gt;
:   → ASSM(Automatic Segment Space Management)이라도 &lt;br /&gt;
     극단적으로 짧은 시간에 너무 많은 세션이 몰리면 발생 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* SecureFile LOB에 다수 세션이 동시에 대용량 데이터를 넣는 배치/API 환경이라면, LOB Segment의 HWM 확장 경쟁이 바로 이 대기 이벤트의 주요 원인&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
===  실습으로 재현해보기 ===&lt;br /&gt;
# 테스트 테이블&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE hw_contention_test (&lt;br /&gt;
    id       NUMBER,&lt;br /&gt;
    data_lob CLOB&lt;br /&gt;
)&lt;br /&gt;
LOB (data_lob) STORE AS SECUREFILE hw_lob_seg (&lt;br /&gt;
    DISABLE STORAGE IN ROW&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 다수 세션에서 동시 INSERT 발생시키기 (개념적 재현)&lt;br /&gt;
#: 여러 세션에서 동시에 아래를 실행 (SQL*Plus 여러 창 or 병렬 Job):&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Session 1~10 동시 실행&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    FOR i IN 1..1000 LOOP&lt;br /&gt;
        l_clob := gen_clob(50000, &#039;X&#039;);  -- 50KB LOB&lt;br /&gt;
        INSERT INTO hw_contention_test VALUES (i, l_clob);&lt;br /&gt;
        COMMIT;&lt;br /&gt;
    END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 실시간 대기 이벤트 모니터링&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT sid, event, state, seconds_in_wait, p1, p2, p3&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SID   EVENT                    STATE    SECONDS_IN_WAIT   P1          P2      P3&lt;br /&gt;
----  -----------------------  -------  ----------------  ----------  ------  ------&lt;br /&gt;
 145  enq: HW - contention     WAITING                 2   1213908993   65543       0&lt;br /&gt;
 152  enq: HW - contention     WAITING                 2   1213908993   65543       0&lt;br /&gt;
 168  enq: HW - contention     WAITING                 1   1213908993   65543       0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:* P1, P2 해석: &lt;br /&gt;
#:*:- `P1 = 1213908993` → `Type=&#039;HW&#039;(0x48 0x57), Mode` 조합 인코딩 값&lt;br /&gt;
#:*:- `P2 = 65543` → 대상 세그먼트의 **Tablespace# + Relative File#** 조합 (같은 세그먼트를 다투고 있다는 증거)&lt;br /&gt;
#:&lt;br /&gt;
#:* 동일한 P2 값을 가진 세션들이 정확히 같은 세그먼트(여기서는 hw_lob_seg)에서 경쟁 중임을 의미합니다.&lt;br /&gt;
# 원인이 되는 세그먼트를 정확히 찾아내는 방법&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- P2 값을 이용해 실제 경쟁 중인 세그먼트 역추적&lt;br /&gt;
SELECT s.sid, s.event, &lt;br /&gt;
       o.owner, o.object_name, o.object_type&lt;br /&gt;
FROM v$session s,&lt;br /&gt;
     v$lock l,&lt;br /&gt;
     dba_extents e,&lt;br /&gt;
     dba_objects o&lt;br /&gt;
WHERE s.event = &#039;enq: HW - contention&#039;&lt;br /&gt;
AND l.sid = s.sid&lt;br /&gt;
AND l.type = &#039;HW&#039;&lt;br /&gt;
AND e.relative_fno = MOD(l.id2, 65536)&lt;br /&gt;
AND e.file_id = e.relative_fno   -- 환경에 맞게 조정 필요&lt;br /&gt;
AND o.object_id = e.segment_id&lt;br /&gt;
AND o.object_name = e.segment_name;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#: * 더 실무적으로 간단한 방법: P1/P2로 직접 조회하는 대신, 실시간으로 어느 세그먼트가 확장 중인지 ASH로 확인&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT sample_time, session_id, &lt;br /&gt;
       current_obj#, &lt;br /&gt;
       (SELECT object_name FROM dba_objects WHERE object_id = ash.current_obj#) AS obj_name,&lt;br /&gt;
       event&lt;br /&gt;
FROM v$active_session_history ash&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
ORDER BY sample_time DESC&lt;br /&gt;
FETCH FIRST 20 ROWS ONLY;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SAMPLE_TIME              SESSION_ID   CURRENT_OBJ#   OBJ_NAME         EVENT&lt;br /&gt;
-----------------------  -----------  -------------  ---------------  ---------------------&lt;br /&gt;
2024-01-15 14:23:01.123          145         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
2024-01-15 14:23:01.456          152         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
2024-01-15 14:23:01.789          168         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 확인 완료 : 세 세션 모두 `HW_LOB_SEG`에서 경쟁 중임이 명확히 드러납니다.&lt;br /&gt;
&lt;br /&gt;
===  왜 이런 구조적 한계가 존재하는가?  (ASSM이라도 못 피하는 이유) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
오해: &amp;quot;ASSM(자동 세그먼트 공간 관리)이면 &lt;br /&gt;
       Freelist Contention이 해결됐으니 HW Contention도 없겠지?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
실제: ASSM은 &amp;quot;이미 HWM 아래에 있는 블록들 사이의 공간 찾기 경쟁&amp;quot;만 해결한다.&lt;br /&gt;
      &amp;quot;HWM 자체를 넘어서 새 영역으로 처음 진입하는 순간&amp;quot;의 &lt;br /&gt;
      직렬화는 ASSM 여부와 무관하게 항상 존재한다.&lt;br /&gt;
&lt;br /&gt;
즉, Freelist Contention(구시대) ≠ HW Contention(구조적으로 항상 존재)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# LOB Segment는 특히 취약한 이유*:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
일반 Table Segment&lt;br /&gt;
→ 여러 세션이 각기 다른 블록에 흩어져서 쓸 수 있음 (ASSM Bitmap 분산 배정)&lt;br /&gt;
→ HWM 확장 빈도 자체가 상대적으로 낮음&lt;br /&gt;
&lt;br /&gt;
LOB Segment (특히 NOCACHE 대용량 INSERT)&lt;br /&gt;
→ 각 LOB 값이 통째로 CHUNK 단위(8K, 16K...)를 즉시 소비&lt;br /&gt;
→ 대용량 LOB을 빠르게 연속 INSERT하면 HWM이 &amp;quot;매우 자주&amp;quot; 이동해야 함&lt;br /&gt;
→ HWM 이동 빈도가 높을수록 Contention 발생 확률 급증&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  해결 방안 (실전 우선순위 순) ===&lt;br /&gt;
# SECUREFILE의 경우 - Concurrency 관련 파라미터 확인&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 LOB의 상세 스토리지 옵션 확인&lt;br /&gt;
SELECT table_name, column_name, securefile, &lt;br /&gt;
       cache, logging, retention&lt;br /&gt;
FROM user_lobs&lt;br /&gt;
WHERE table_name = &#039;HW_CONTENTION_TEST&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
TABLE_NAME            COLUMN_NAME  SECUREFILE  CACHE      LOGGING  RETENTION&lt;br /&gt;
--------------------  -----------  ----------  ---------  -------  ----------&lt;br /&gt;
HW_CONTENTION_TEST    DATA_LOB     YES         NO         YES      AUTO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:*개선안: SecureFile은 내부적으로 Space Management를 위한 여러 최적화가 있지만, 극단적 동시성에서는 여전히 근본적 해결이 안 됨. 아래 항목들과 병행 필요.&lt;br /&gt;
#  파티셔닝으로 세그먼트 자체를 분산 (가장 효과적)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Hash Partition으로 LOB Segment 자체를 물리적으로 분산&lt;br /&gt;
CREATE TABLE hw_contention_test_part (&lt;br /&gt;
    id       NUMBER,&lt;br /&gt;
    data_lob CLOB&lt;br /&gt;
)&lt;br /&gt;
LOB (data_lob) STORE AS SECUREFILE (&lt;br /&gt;
    DISABLE STORAGE IN ROW&lt;br /&gt;
    NOCACHE&lt;br /&gt;
)&lt;br /&gt;
PARTITION BY HASH (id) PARTITIONS 8;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 파티션별로 별도의 LOB Segment가 생성되는지 확인&lt;br /&gt;
SELECT table_name, partition_name, segment_name&lt;br /&gt;
FROM user_lob_partitions&lt;br /&gt;
WHERE table_name = &#039;HW_CONTENTION_TEST_PART&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
TABLE_NAME                PARTITION_NAME   SEGMENT_NAME&lt;br /&gt;
-------------------------  ---------------  ------------------------&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P101         SYS_LOB_P101_00001$$&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P102         SYS_LOB_P102_00002$$&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P103         SYS_LOB_P103_00003$$&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 효과 : 세션들이 `id` 값에 따라 8개의 서로 다른 파티션(=서로 다른 LOB Segment)으로 흩어지므로, 동일 세그먼트를 다투는 확률이 1/8로 감소합니다.&lt;br /&gt;
# 동시 INSERT 세션 수 자체를 조절 (애플리케이션 레벨)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Resource Manager로 동시 병렬도 제한 (배치 작업의 경우)&lt;br /&gt;
BEGIN&lt;br /&gt;
  DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(&lt;br /&gt;
    plan =&amp;gt; &#039;BATCH_PLAN&#039;,&lt;br /&gt;
    group_or_subplan =&amp;gt; &#039;BATCH_GROUP&#039;,&lt;br /&gt;
    comment =&amp;gt; &#039;LOB Insert 동시성 제한&#039;,&lt;br /&gt;
    parallel_degree_limit_p1 =&amp;gt; 4  -- 동시 병렬도 제한&lt;br /&gt;
  );&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# CACHE 옵션 재검토 (단, 대용량이면 신중히)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- NOCACHE → CACHE READS로 변경 시 HWM 확장 패턴이 달라질 수 있음&lt;br /&gt;
-- (단, Buffer Cache 압박이 커지므로 LOB이 매우 크면 비추천)&lt;br /&gt;
ALTER TABLE hw_contention_test MOVE LOB(data_lob) STORE AS (&lt;br /&gt;
    CACHE READS&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
# 배치 커밋 간격 조정 (Commit 빈도와 HWM 확장 빈도는 별개지만 병행 효과 있음)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 매 row마다 COMMIT → 500 row마다 COMMIT으로 변경&lt;br /&gt;
-- (트랜잭션 오버헤드 감소로 전체 처리시간 단축, HW Contention 절대량은 불변이나 &lt;br /&gt;
--  세션 간 타이밍이 분산되어 충돌 확률 감소하는 부수 효과)&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    FOR i IN 1..1000 LOOP&lt;br /&gt;
        l_clob := gen_clob(50000, &#039;X&#039;);&lt;br /&gt;
        INSERT INTO hw_contention_test VALUES (i, l_clob);&lt;br /&gt;
        IF MOD(i, 500) = 0 THEN&lt;br /&gt;
            COMMIT;&lt;br /&gt;
        END IF;&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 실전 진단 체크리스트&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 HW Contention이 Top Wait Event로 잡히는지 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS time_waited_sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
AND snap_id BETWEEN (SELECT MIN(snap_id) FROM dba_hist_snapshot WHERE begin_interval_time &amp;gt; SYSDATE-1)&lt;br /&gt;
                AND (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY time_waited_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
EVENT                    TOTAL_WAITS   TIME_WAITED_SEC&lt;br /&gt;
-----------------------  ------------  ----------------&lt;br /&gt;
enq: HW - contention             8421            342.56&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이 정도 수치(하루 5분 이상 누적 대기)라면 명백히 튜닝 대상 입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 최종 정리 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: HW - contention 핵심 요약&lt;br /&gt;
&lt;br /&gt;
원인: 세그먼트의 High Water Mark를 넘어 새 영역으로 확장할 때 &lt;br /&gt;
      발생하는 필연적 직렬화 경쟁&lt;br /&gt;
&lt;br /&gt;
가장 흔한 실전 상황: 다수 세션의 동시 LOB INSERT (특히 NOCACHE 대용량)&lt;br /&gt;
&lt;br /&gt;
ASSM으로도 해결 안 되는 구조적 이슈 (Freelist Contention과는 다른 문제)&lt;br /&gt;
&lt;br /&gt;
가장 효과적인 해결책 우선순위:&lt;br /&gt;
  1. 파티셔닝으로 세그먼트 자체를 분산 (근본 해결)&lt;br /&gt;
  2. 동시 세션 수/병렬도 제한 (부하 조절)&lt;br /&gt;
  3. CACHE 옵션, 배치 커밋 조정 (보조적 완화)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Enq:hw-contention&amp;diff=1914</id>
		<title>Enq:hw-contention</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Enq:hw-contention&amp;diff=1914"/>
		<updated>2026-09-21T23:33:40Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: == enq: HW - Contention == * LOB Segment 이슈와 밀접하게 연결되는 대기 이벤트입니다.  * 특히 동시성 높은 환경에서 LOB 컬럼에 INSERT가 몰릴 때 자주 발생하는 이슈  ---- === HW(High Water Mark) Enqueue가 무엇인가?  === * 개념: 세그먼트(Table, Index, LOB Segment 등)가 &amp;quot;새로운 블록 영역으로 확장&amp;quot; 될 때 걸리는 직렬화 락(Lock)  * HWM(High Water Mark)란? := 이 세그먼트가 지금까지 한 번이라도...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== enq: HW - Contention ==&lt;br /&gt;
* LOB Segment 이슈와 밀접하게 연결되는 대기 이벤트입니다. &lt;br /&gt;
* 특히 동시성 높은 환경에서 LOB 컬럼에 INSERT가 몰릴 때 자주 발생하는 이슈&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== HW(High Water Mark) Enqueue가 무엇인가?  ===&lt;br /&gt;
* 개념: 세그먼트(Table, Index, LOB Segment 등)가 &amp;quot;새로운 블록 영역으로 확장&amp;quot; 될 때 걸리는 직렬화 락(Lock)&lt;br /&gt;
&lt;br /&gt;
* HWM(High Water Mark)란?&lt;br /&gt;
:= 이 세그먼트가 지금까지 한 번이라도 사용한 적 있는 블록의 최대 경계선&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
[세그먼트 내부 이미지]&lt;br /&gt;
┌────────┬────────┬────────┬────────┬─────────────┐&lt;br /&gt;
│ 사용중 │ 사용중 │ 사용중  │ 미사용  │   미사용    │&lt;br /&gt;
│ Block1 │ Block2 │ Block3 │ Block4 │   Block5    │&lt;br /&gt;
└────────┴────────┴────────┴────────┴─────────────┘&lt;br /&gt;
                            ▲&lt;br /&gt;
                           HWM (여기까지가 &amp;quot;사용해본 적 있는&amp;quot; 경계)&lt;br /&gt;
&lt;br /&gt;
→ HWM을 넘어 Block4, Block5로 최초 진입(확장)하려면 &lt;br /&gt;
  &amp;quot;누군가 한 명만&amp;quot; HWM을 이동시키는 작업을 해야 함&lt;br /&gt;
→ 그 &amp;quot;한 명만 하도록 강제&amp;quot;하는 직렬화 장치가 바로 enq: HW 이다&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*핵심: HW 이동 자체는 원자적(Atomic)이어야 하므로, 여러 세션이 동시에 HWM을 넘기려고 시도하면 한 세션만 실제로 이동시키고 나머지는 대기합니다. &lt;br /&gt;
이 대기가 `enq: HW - contention`입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 어떤 상황에서 자주 발생하는가? ===&lt;br /&gt;
&lt;br /&gt;
# 발생 빈발 시나리오 TOP 3&lt;br /&gt;
#:&amp;lt;source&amp;gt;&lt;br /&gt;
1순위: LOB Segment 동시 INSERT (가장 빈번)&lt;br /&gt;
:   → 여러 세션이 동시에 CLOB/BLOB 컬럼에 대량 데이터를 INSERT&lt;br /&gt;
:   → 특히 NOCACHE + 병렬 세션 조합에서 극심&lt;br /&gt;
&lt;br /&gt;
2순위: 병렬 Direct-Path INSERT (APPEND Hint)&lt;br /&gt;
 :  → 여러 병렬 슬레이브가 동시에 같은 테이블 뒤쪽에 데이터 적재&lt;br /&gt;
&lt;br /&gt;
3순위: 시퀀스 없는 대량 동시 INSERT (일반 Heap 테이블)&lt;br /&gt;
:   → ASSM(Automatic Segment Space Management)이라도 &lt;br /&gt;
     극단적으로 짧은 시간에 너무 많은 세션이 몰리면 발생 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* SecureFile LOB에 다수 세션이 동시에 대용량 데이터를 넣는 배치/API 환경이라면, LOB Segment의 HWM 확장 경쟁이 바로 이 대기 이벤트의 주요 원인&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
===  실습으로 재현해보기 ===&lt;br /&gt;
# 테스트 테이블&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE hw_contention_test (&lt;br /&gt;
    id       NUMBER,&lt;br /&gt;
    data_lob CLOB&lt;br /&gt;
)&lt;br /&gt;
LOB (data_lob) STORE AS SECUREFILE hw_lob_seg (&lt;br /&gt;
    DISABLE STORAGE IN ROW&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 다수 세션에서 동시 INSERT 발생시키기 (개념적 재현)&lt;br /&gt;
#: 여러 세션에서 동시에 아래를 실행 (SQL*Plus 여러 창 or 병렬 Job):&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Session 1~10 동시 실행&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    FOR i IN 1..1000 LOOP&lt;br /&gt;
        l_clob := gen_clob(50000, &#039;X&#039;);  -- 50KB LOB&lt;br /&gt;
        INSERT INTO hw_contention_test VALUES (i, l_clob);&lt;br /&gt;
        COMMIT;&lt;br /&gt;
    END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 실시간 대기 이벤트 모니터링&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT sid, event, state, seconds_in_wait, p1, p2, p3&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SID   EVENT                    STATE    SECONDS_IN_WAIT   P1          P2      P3&lt;br /&gt;
----  -----------------------  -------  ----------------  ----------  ------  ------&lt;br /&gt;
 145  enq: HW - contention     WAITING                 2   1213908993   65543       0&lt;br /&gt;
 152  enq: HW - contention     WAITING                 2   1213908993   65543       0&lt;br /&gt;
 168  enq: HW - contention     WAITING                 1   1213908993   65543       0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:* P1, P2 해석: &lt;br /&gt;
#:*:- `P1 = 1213908993` → `Type=&#039;HW&#039;(0x48 0x57), Mode` 조합 인코딩 값&lt;br /&gt;
#:*:- `P2 = 65543` → 대상 세그먼트의 **Tablespace# + Relative File#** 조합 (같은 세그먼트를 다투고 있다는 증거)&lt;br /&gt;
#:&lt;br /&gt;
#:* 동일한 P2 값을 가진 세션들이 정확히 같은 세그먼트(여기서는 hw_lob_seg)에서 경쟁 중임을 의미합니다.&lt;br /&gt;
# 원인이 되는 세그먼트를 정확히 찾아내는 방법&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- P2 값을 이용해 실제 경쟁 중인 세그먼트 역추적&lt;br /&gt;
SELECT s.sid, s.event, &lt;br /&gt;
       o.owner, o.object_name, o.object_type&lt;br /&gt;
FROM v$session s,&lt;br /&gt;
     v$lock l,&lt;br /&gt;
     dba_extents e,&lt;br /&gt;
     dba_objects o&lt;br /&gt;
WHERE s.event = &#039;enq: HW - contention&#039;&lt;br /&gt;
AND l.sid = s.sid&lt;br /&gt;
AND l.type = &#039;HW&#039;&lt;br /&gt;
AND e.relative_fno = MOD(l.id2, 65536)&lt;br /&gt;
AND e.file_id = e.relative_fno   -- 환경에 맞게 조정 필요&lt;br /&gt;
AND o.object_id = e.segment_id&lt;br /&gt;
AND o.object_name = e.segment_name;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#: * 더 실무적으로 간단한 방법: P1/P2로 직접 조회하는 대신, 실시간으로 어느 세그먼트가 확장 중인지 ASH로 확인&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT sample_time, session_id, &lt;br /&gt;
       current_obj#, &lt;br /&gt;
       (SELECT object_name FROM dba_objects WHERE object_id = ash.current_obj#) AS obj_name,&lt;br /&gt;
       event&lt;br /&gt;
FROM v$active_session_history ash&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
ORDER BY sample_time DESC&lt;br /&gt;
FETCH FIRST 20 ROWS ONLY;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SAMPLE_TIME              SESSION_ID   CURRENT_OBJ#   OBJ_NAME         EVENT&lt;br /&gt;
-----------------------  -----------  -------------  ---------------  ---------------------&lt;br /&gt;
2024-01-15 14:23:01.123          145         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
2024-01-15 14:23:01.456          152         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
2024-01-15 14:23:01.789          168         123457   HW_LOB_SEG       enq: HW - contention&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 확인 완료 : 세 세션 모두 `HW_LOB_SEG`에서 경쟁 중임이 명확히 드러납니다.&lt;br /&gt;
&lt;br /&gt;
===  왜 이런 구조적 한계가 존재하는가?  (ASSM이라도 못 피하는 이유) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
오해: &amp;quot;ASSM(자동 세그먼트 공간 관리)이면 &lt;br /&gt;
       Freelist Contention이 해결됐으니 HW Contention도 없겠지?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
실제: ASSM은 &amp;quot;이미 HWM 아래에 있는 블록들 사이의 공간 찾기 경쟁&amp;quot;만 해결한다.&lt;br /&gt;
      &amp;quot;HWM 자체를 넘어서 새 영역으로 처음 진입하는 순간&amp;quot;의 &lt;br /&gt;
      직렬화는 ASSM 여부와 무관하게 항상 존재한다.&lt;br /&gt;
&lt;br /&gt;
즉, Freelist Contention(구시대) ≠ HW Contention(구조적으로 항상 존재)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# LOB Segment는 특히 취약한 이유*:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
일반 Table Segment&lt;br /&gt;
→ 여러 세션이 각기 다른 블록에 흩어져서 쓸 수 있음 (ASSM Bitmap 분산 배정)&lt;br /&gt;
→ HWM 확장 빈도 자체가 상대적으로 낮음&lt;br /&gt;
&lt;br /&gt;
LOB Segment (특히 NOCACHE 대용량 INSERT)&lt;br /&gt;
→ 각 LOB 값이 통째로 CHUNK 단위(8K, 16K...)를 즉시 소비&lt;br /&gt;
→ 대용량 LOB을 빠르게 연속 INSERT하면 HWM이 &amp;quot;매우 자주&amp;quot; 이동해야 함&lt;br /&gt;
→ HWM 이동 빈도가 높을수록 Contention 발생 확률 급증&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  해결 방안 (실전 우선순위 순) ===&lt;br /&gt;
# SECUREFILE의 경우 - Concurrency 관련 파라미터 확인&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 LOB의 상세 스토리지 옵션 확인&lt;br /&gt;
SELECT table_name, column_name, securefile, &lt;br /&gt;
       cache, logging, retention&lt;br /&gt;
FROM user_lobs&lt;br /&gt;
WHERE table_name = &#039;HW_CONTENTION_TEST&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
TABLE_NAME            COLUMN_NAME  SECUREFILE  CACHE      LOGGING  RETENTION&lt;br /&gt;
--------------------  -----------  ----------  ---------  -------  ----------&lt;br /&gt;
HW_CONTENTION_TEST    DATA_LOB     YES         NO         YES      AUTO&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:*개선안: SecureFile은 내부적으로 Space Management를 위한 여러 최적화가 있지만, 극단적 동시성에서는 여전히 근본적 해결이 안 됨. 아래 항목들과 병행 필요.&lt;br /&gt;
#  파티셔닝으로 세그먼트 자체를 분산 (가장 효과적)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Hash Partition으로 LOB Segment 자체를 물리적으로 분산&lt;br /&gt;
CREATE TABLE hw_contention_test_part (&lt;br /&gt;
    id       NUMBER,&lt;br /&gt;
    data_lob CLOB&lt;br /&gt;
)&lt;br /&gt;
LOB (data_lob) STORE AS SECUREFILE (&lt;br /&gt;
    DISABLE STORAGE IN ROW&lt;br /&gt;
    NOCACHE&lt;br /&gt;
)&lt;br /&gt;
PARTITION BY HASH (id) PARTITIONS 8;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 파티션별로 별도의 LOB Segment가 생성되는지 확인&lt;br /&gt;
SELECT table_name, partition_name, segment_name&lt;br /&gt;
FROM user_lob_partitions&lt;br /&gt;
WHERE table_name = &#039;HW_CONTENTION_TEST_PART&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
TABLE_NAME                PARTITION_NAME   SEGMENT_NAME&lt;br /&gt;
-------------------------  ---------------  ------------------------&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P101         SYS_LOB_P101_00001$$&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P102         SYS_LOB_P102_00002$$&lt;br /&gt;
HW_CONTENTION_TEST_PART    SYS_P103         SYS_LOB_P103_00003$$&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 효과 : 세션들이 `id` 값에 따라 8개의 서로 다른 파티션(=서로 다른 LOB Segment)으로 흩어지므로, 동일 세그먼트를 다투는 확률이 1/8로 감소합니다.&lt;br /&gt;
# 동시 INSERT 세션 수 자체를 조절 (애플리케이션 레벨)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Resource Manager로 동시 병렬도 제한 (배치 작업의 경우)&lt;br /&gt;
BEGIN&lt;br /&gt;
  DBMS_RESOURCE_MANAGER.CREATE_PLAN_DIRECTIVE(&lt;br /&gt;
    plan =&amp;gt; &#039;BATCH_PLAN&#039;,&lt;br /&gt;
    group_or_subplan =&amp;gt; &#039;BATCH_GROUP&#039;,&lt;br /&gt;
    comment =&amp;gt; &#039;LOB Insert 동시성 제한&#039;,&lt;br /&gt;
    parallel_degree_limit_p1 =&amp;gt; 4  -- 동시 병렬도 제한&lt;br /&gt;
  );&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# CACHE 옵션 재검토 (단, 대용량이면 신중히)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- NOCACHE → CACHE READS로 변경 시 HWM 확장 패턴이 달라질 수 있음&lt;br /&gt;
-- (단, Buffer Cache 압박이 커지므로 LOB이 매우 크면 비추천)&lt;br /&gt;
ALTER TABLE hw_contention_test MOVE LOB(data_lob) STORE AS (&lt;br /&gt;
    CACHE READS&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
# 배치 커밋 간격 조정 (Commit 빈도와 HWM 확장 빈도는 별개지만 병행 효과 있음)&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 매 row마다 COMMIT → 500 row마다 COMMIT으로 변경&lt;br /&gt;
-- (트랜잭션 오버헤드 감소로 전체 처리시간 단축, HW Contention 절대량은 불변이나 &lt;br /&gt;
--  세션 간 타이밍이 분산되어 충돌 확률 감소하는 부수 효과)&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    FOR i IN 1..1000 LOOP&lt;br /&gt;
        l_clob := gen_clob(50000, &#039;X&#039;);&lt;br /&gt;
        INSERT INTO hw_contention_test VALUES (i, l_clob);&lt;br /&gt;
        IF MOD(i, 500) = 0 THEN&lt;br /&gt;
            COMMIT;&lt;br /&gt;
        END IF;&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 실전 진단 체크리스트&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 HW Contention이 Top Wait Event로 잡히는지 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS time_waited_sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
AND snap_id BETWEEN (SELECT MIN(snap_id) FROM dba_hist_snapshot WHERE begin_interval_time &amp;gt; SYSDATE-1)&lt;br /&gt;
                AND (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY time_waited_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
EVENT                    TOTAL_WAITS   TIME_WAITED_SEC&lt;br /&gt;
-----------------------  ------------  ----------------&lt;br /&gt;
enq: HW - contention             8421            342.56&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이 정도 수치(하루 5분 이상 누적 대기)라면 명백히 튜닝 대상 입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 최종 정리 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: HW - contention 핵심 요약&lt;br /&gt;
&lt;br /&gt;
원인: 세그먼트의 High Water Mark를 넘어 새 영역으로 확장할 때 &lt;br /&gt;
      발생하는 필연적 직렬화 경쟁&lt;br /&gt;
&lt;br /&gt;
가장 흔한 실전 상황: 다수 세션의 동시 LOB INSERT (특히 NOCACHE 대용량)&lt;br /&gt;
&lt;br /&gt;
ASSM으로도 해결 안 되는 구조적 이슈 (Freelist Contention과는 다른 문제)&lt;br /&gt;
&lt;br /&gt;
가장 효과적인 해결책 우선순위:&lt;br /&gt;
  1. 파티셔닝으로 세그먼트 자체를 분산 (근본 해결)&lt;br /&gt;
  2. 동시 세션 수/병렬도 제한 (부하 조절)&lt;br /&gt;
  3. CACHE 옵션, 배치 커밋 조정 (보조적 완화)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1913</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1913"/>
		<updated>2026-09-16T09:35:53Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace || ASSM (AUTO Segment Space Management) 여부 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type || SecureFile 사용 여부 (BasicFile 지양) &lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 || 큰 NEXT 값으로 HW 이동 빈도 최소화 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 || 가능하면 노드/워크로드 특성 따라 분산 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 || 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) &lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION || PCTVERSION 대신 RETENTION 사용 검토 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 || HW/gc buffer busy 이벤트 정기 추적 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
{{결론&lt;br /&gt;
|내용=핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1912</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1912"/>
		<updated>2026-09-16T09:33:37Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace || ASSM (AUTO Segment Space Management) 여부 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type || SecureFile 사용 여부 (BasicFile 지양) &lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 || 큰 NEXT 값으로 HW 이동 빈도 최소화 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 || 가능하면 노드/워크로드 특성 따라 분산 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 || 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) &lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION || PCTVERSION 대신 RETENTION 사용 검토 &lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 || HW/gc buffer busy 이벤트 정기 추적 &lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
{{결론&lt;br /&gt;
|내용=핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1911</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1911"/>
		<updated>2026-09-16T09:32:41Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace || ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type || SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 || 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 || 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 || 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION || PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 || HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
{{결론&lt;br /&gt;
|내용=핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1910</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1910"/>
		<updated>2026-09-16T09:30:43Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* LOB의 3단 구조가 만드는 3중 경합 지점 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace || ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type || SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 || 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 || 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 || 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION || PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 || HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1909</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1909"/>
		<updated>2026-09-16T09:30:27Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace || ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type || SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 || 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 || 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 || 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION || PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 || HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1908</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1908"/>
		<updated>2026-09-16T09:29:17Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
{| class=”wikitable“&lt;br /&gt;
|- &lt;br /&gt;
! 항목 !! 확인 사항&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
|-&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
|}&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1832</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1832"/>
		<updated>2026-09-15T23:30:39Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1831</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1831"/>
		<updated>2026-09-15T23:25:10Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 반드시 ASSM 사용해야 하는 이유 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! MSSM (FREELIST) !! ASSM (Bitmap) &lt;br /&gt;
|-&lt;br /&gt;
| RAC 확장성 || FREELIST GROUPS 수동 구성 필요 || 자동으로 인스턴스별 분산 &lt;br /&gt;
|-&lt;br /&gt;
| HW 경합 || 매우 심함 || 상대적으로 완화 &lt;br /&gt;
|-&lt;br /&gt;
| 권장 여부 || ❌ RAC에서 지양 || ✅ 필수 권장 &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Lob_chunk_size_%EC%B5%9C%EC%A0%81%ED%99%94_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1830</id>
		<title>Lob chunk size 최적화 테스트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Lob_chunk_size_%EC%B5%9C%EC%A0%81%ED%99%94_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1830"/>
		<updated>2026-09-15T03:47:14Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT&lt;br /&gt;
    MIN(DBMS_LOB.GETLENGTH(doc))    AS min_len,&lt;br /&gt;
    ROUND(AVG(DBMS_LOB.GETLENGTH(doc))) AS avg_len,&lt;br /&gt;
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS median_len,&lt;br /&gt;
    PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS p90_len,&lt;br /&gt;
    MAX(DBMS_LOB.GETLENGTH(doc))    AS max_len&lt;br /&gt;
FROM 실제테이블 SAMPLE(5)&lt;br /&gt;
WHERE doc IS NOT NULL;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================================&lt;br /&gt;
-- LOB CHUNK 크기 최적화 - 후보 값 실측 비교 스크립트&lt;br /&gt;
-- 목적: 여러 CHUNK 후보값에 대해 INSERT/SELECT 성능과&lt;br /&gt;
--       공간 효율(fragmentation)을 동일 조건에서 비교 측정&lt;br /&gt;
-- 방법: 테이블 1개를 두고 후보 CHUNK 값마다&lt;br /&gt;
--       TRUNCATE -&amp;gt; MOVE LOB(CHUNK 변경) -&amp;gt; 동일 데이터 INSERT&lt;br /&gt;
--       -&amp;gt; INSERT/SELECT 시간, 공간 사용량 측정을 반복&lt;br /&gt;
-- 실행 전: 4번 TEST_LOB_SIZE 값을 실제 워크로드의 대표 크기&lt;br /&gt;
--          (1번 분포조사에서 나온 median/avg 값)로 맞춰서 실행&lt;br /&gt;
-- ============================================================&lt;br /&gt;
&lt;br /&gt;
SET SERVEROUTPUT ON SIZE UNLIMITED&lt;br /&gt;
SET TIMING OFF&lt;br /&gt;
SET LINESIZE 200&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 0. 정리 및 테이블 생성&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
BEGIN&lt;br /&gt;
    EXECUTE IMMEDIATE &#039;DROP TABLE CHUNK_TEST_TBL PURGE&#039;;&lt;br /&gt;
EXCEPTION&lt;br /&gt;
    WHEN OTHERS THEN&lt;br /&gt;
        IF SQLCODE != -942 THEN RAISE; END IF;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE CHUNK_TEST_TBL (&lt;br /&gt;
    id  NUMBER NOT NULL,&lt;br /&gt;
    doc CLOB,&lt;br /&gt;
    CONSTRAINT pk_chunk_test PRIMARY KEY (id)&lt;br /&gt;
)&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE chunk_test_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_PIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 1. 테스트 실행 (후보 CHUNK 값마다 반복)&lt;br /&gt;
--    TEST_LOB_SIZE : 실제 워크로드 대표 크기(byte)로 조정할 것&lt;br /&gt;
--    ROW_COUNT     : 반복 횟수(너무 크면 시간이 오래 걸림, 1000~5000 권장)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    TYPE t_chunk_list IS TABLE OF NUMBER;&lt;br /&gt;
    v_chunks       t_chunk_list := t_chunk_list(8192, 32768, 131072, 1048576);&lt;br /&gt;
                                -- 8K,      32K,       128K,     1M   -- 필요시 후보 추가/조정&lt;br /&gt;
&lt;br /&gt;
    c_test_lob_size CONSTANT PLS_INTEGER := 50000;  -- &amp;lt;&amp;lt;&amp;lt; 실제 대표 크기로 조정&lt;br /&gt;
    c_row_count     CONSTANT PLS_INTEGER := 2000;&lt;br /&gt;
&lt;br /&gt;
    v_start_time  NUMBER;&lt;br /&gt;
    v_ins_sec     NUMBER;&lt;br /&gt;
    v_sel_sec     NUMBER;&lt;br /&gt;
    v_start_pio   NUMBER;&lt;br /&gt;
    v_pio_ins     NUMBER;&lt;br /&gt;
    v_pio_sel     NUMBER;&lt;br /&gt;
    v_seg_bytes   NUMBER;&lt;br /&gt;
    v_actual_bytes NUMBER;&lt;br /&gt;
    v_frag_pct    NUMBER;&lt;br /&gt;
    v_sum_len     NUMBER;&lt;br /&gt;
    v_doc         CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_doc := RPAD(&#039;X&#039;, c_test_lob_size, &#039;X&#039;);&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(RPAD(&#039;CHUNK(byte)&#039;,12) || RPAD(&#039;INSERT(초)&#039;,12) ||&lt;br /&gt;
                          RPAD(&#039;SELECT(초)&#039;,12) || RPAD(&#039;물리IO(SEL)&#039;,12) ||&lt;br /&gt;
                          RPAD(&#039;세그먼트(MB)&#039;,14) || &#039;데이터대비 오버헤드(%)&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(RPAD(&#039;-&#039;,90,&#039;-&#039;));&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_chunks.COUNT LOOP&lt;br /&gt;
        -- (1) 초기화 + CHUNK 변경&lt;br /&gt;
        EXECUTE IMMEDIATE &#039;TRUNCATE TABLE CHUNK_TEST_TBL&#039;;&lt;br /&gt;
        EXECUTE IMMEDIATE&lt;br /&gt;
            &#039;ALTER TABLE CHUNK_TEST_TBL MOVE LOB (doc) STORE AS (CHUNK &#039; || v_chunks(i) || &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
        -- (2) INSERT 성능 측정&lt;br /&gt;
        v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
        FOR r IN 1 .. c_row_count LOOP&lt;br /&gt;
            INSERT INTO CHUNK_TEST_TBL (id, doc) VALUES (r, v_doc);&lt;br /&gt;
        END LOOP;&lt;br /&gt;
        COMMIT;&lt;br /&gt;
        v_ins_sec := (DBMS_UTILITY.GET_TIME - v_start_time) / 100;&lt;br /&gt;
&lt;br /&gt;
        EXECUTE IMMEDIATE&lt;br /&gt;
            &#039;BEGIN DBMS_STATS.GATHER_TABLE_STATS(:o, :t, CASCADE =&amp;gt; TRUE); END;&#039;&lt;br /&gt;
            USING USER, &#039;CHUNK_TEST_TBL&#039;;&lt;br /&gt;
&lt;br /&gt;
        -- (3) SELECT(전체 읽기) 성능 측정&lt;br /&gt;
        v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
        v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
        SELECT SUM(DBMS_LOB.GETLENGTH(doc)) INTO v_sum_len FROM CHUNK_TEST_TBL;&lt;br /&gt;
        v_sel_sec := (DBMS_UTILITY.GET_TIME - v_start_time) / 100;&lt;br /&gt;
        v_pio_sel := GET_SESS_PIO - v_start_pio;&lt;br /&gt;
&lt;br /&gt;
        -- (4) 공간 사용량(세그먼트 크기) 및 오버헤드 비율&lt;br /&gt;
        SELECT bytes INTO v_seg_bytes&lt;br /&gt;
        FROM dba_segments&lt;br /&gt;
        WHERE owner = USER AND segment_name = &#039;CHUNK_TEST_LSEG&#039;;&lt;br /&gt;
&lt;br /&gt;
        v_actual_bytes := c_test_lob_size * c_row_count;&lt;br /&gt;
        v_frag_pct := ROUND((v_seg_bytes - v_actual_bytes) / v_actual_bytes * 100, 1);&lt;br /&gt;
&lt;br /&gt;
        DBMS_OUTPUT.PUT_LINE(&lt;br /&gt;
            RPAD(v_chunks(i), 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(v_ins_sec, &#039;999.99&#039;), 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(v_sel_sec, &#039;999.99&#039;), 12) ||&lt;br /&gt;
            RPAD(v_pio_sel, 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(ROUND(v_seg_bytes/1024/1024, 2), &#039;99999.99&#039;), 14) ||&lt;br /&gt;
            TO_CHAR(v_frag_pct)&lt;br /&gt;
        );&lt;br /&gt;
    END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 2. 결과 해석 가이드&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- - INSERT(초)      : CHUNK가 너무 작으면 청크 개수가 늘어 관리 오버헤드 증가,&lt;br /&gt;
--                      너무 크면 큰 단위 할당 비용으로 오히려 느려질 수 있음&lt;br /&gt;
-- - SELECT(초)/물리IO: CHUNK가 데이터 크기에 비해 작을수록 여러 청크를&lt;br /&gt;
--                      나눠 읽어 물리IO 횟수가 늘어나는 경향&lt;br /&gt;
-- - 오버헤드(%)      : (세그먼트 실제 크기 - 순수 데이터 크기) / 데이터 크기&lt;br /&gt;
--                      CHUNK가 데이터보다 훨씬 크면 이 값이 커짐(공간 낭비)&lt;br /&gt;
--                      예: 데이터 50KB인데 CHUNK 1MB면 매 LOB이 1MB를 점유&lt;br /&gt;
--&lt;br /&gt;
-- 최적점은 보통 &amp;quot;오버헤드(%)가 과도하게 커지기 직전이면서&lt;br /&gt;
-- SELECT 물리IO가 충분히 낮아지는 지점&amp;quot;입니다.&lt;br /&gt;
-- 아래처럼 여러 대표 크기(작음/중간/큼)로 각각 돌려서&lt;br /&gt;
-- 실제 운영 중 크기 분포에 맞는 값을 찾는 것을 권장합니다.&lt;br /&gt;
--   c_test_lob_size를 3번 조정해서(예: 2000, 50000, 500000) 재실행&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 3. 정리&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- DROP TABLE CHUNK_TEST_TBL PURGE;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_PIO;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Lob_chunk_size_%EC%B5%9C%EC%A0%81%ED%99%94_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1829</id>
		<title>Lob chunk size 최적화 테스트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Lob_chunk_size_%EC%B5%9C%EC%A0%81%ED%99%94_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1829"/>
		<updated>2026-09-15T03:22:42Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: SELECT     MIN(DBMS_LOB.GETLENGTH(doc))    AS min_len,     ROUND(AVG(DBMS_LOB.GETLENGTH(doc))) AS avg_len,     PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS median_len,     PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS p90_len,     MAX(DBMS_LOB.GETLENGTH(doc))    AS max_len FROM 실제테이블 SAMPLE(5) WHERE doc IS NOT NULL;  &amp;lt;source lang=sql&amp;gt; -- ============================================================ -- LOB CHUNK 크기...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SELECT&lt;br /&gt;
    MIN(DBMS_LOB.GETLENGTH(doc))    AS min_len,&lt;br /&gt;
    ROUND(AVG(DBMS_LOB.GETLENGTH(doc))) AS avg_len,&lt;br /&gt;
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS median_len,&lt;br /&gt;
    PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY DBMS_LOB.GETLENGTH(doc)) AS p90_len,&lt;br /&gt;
    MAX(DBMS_LOB.GETLENGTH(doc))    AS max_len&lt;br /&gt;
FROM 실제테이블 SAMPLE(5)&lt;br /&gt;
WHERE doc IS NOT NULL;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================================&lt;br /&gt;
-- LOB CHUNK 크기 최적화 - 후보 값 실측 비교 스크립트&lt;br /&gt;
-- 목적: 여러 CHUNK 후보값에 대해 INSERT/SELECT 성능과&lt;br /&gt;
--       공간 효율(fragmentation)을 동일 조건에서 비교 측정&lt;br /&gt;
-- 방법: 테이블 1개를 두고 후보 CHUNK 값마다&lt;br /&gt;
--       TRUNCATE -&amp;gt; MOVE LOB(CHUNK 변경) -&amp;gt; 동일 데이터 INSERT&lt;br /&gt;
--       -&amp;gt; INSERT/SELECT 시간, 공간 사용량 측정을 반복&lt;br /&gt;
-- 실행 전: 4번 TEST_LOB_SIZE 값을 실제 워크로드의 대표 크기&lt;br /&gt;
--          (1번 분포조사에서 나온 median/avg 값)로 맞춰서 실행&lt;br /&gt;
-- ============================================================&lt;br /&gt;
&lt;br /&gt;
SET SERVEROUTPUT ON SIZE UNLIMITED&lt;br /&gt;
SET TIMING OFF&lt;br /&gt;
SET LINESIZE 200&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 0. 정리 및 테이블 생성&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
BEGIN&lt;br /&gt;
    EXECUTE IMMEDIATE &#039;DROP TABLE CHUNK_TEST_TBL PURGE&#039;;&lt;br /&gt;
EXCEPTION&lt;br /&gt;
    WHEN OTHERS THEN&lt;br /&gt;
        IF SQLCODE != -942 THEN RAISE; END IF;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE CHUNK_TEST_TBL (&lt;br /&gt;
    id  NUMBER NOT NULL,&lt;br /&gt;
    doc CLOB,&lt;br /&gt;
    CONSTRAINT pk_chunk_test PRIMARY KEY (id)&lt;br /&gt;
)&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE chunk_test_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_PIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 1. 테스트 실행 (후보 CHUNK 값마다 반복)&lt;br /&gt;
--    TEST_LOB_SIZE : 실제 워크로드 대표 크기(byte)로 조정할 것&lt;br /&gt;
--    ROW_COUNT     : 반복 횟수(너무 크면 시간이 오래 걸림, 1000~5000 권장)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    TYPE t_chunk_list IS TABLE OF NUMBER;&lt;br /&gt;
    v_chunks       t_chunk_list := t_chunk_list(8192, 32768, 131072, 1048576);&lt;br /&gt;
                                -- 8K,      32K,       128K,     1M   -- 필요시 후보 추가/조정&lt;br /&gt;
&lt;br /&gt;
    c_test_lob_size CONSTANT PLS_INTEGER := 50000;  -- &amp;lt;&amp;lt;&amp;lt; 실제 대표 크기로 조정&lt;br /&gt;
    c_row_count     CONSTANT PLS_INTEGER := 2000;&lt;br /&gt;
&lt;br /&gt;
    v_start_time  NUMBER;&lt;br /&gt;
    v_ins_sec     NUMBER;&lt;br /&gt;
    v_sel_sec     NUMBER;&lt;br /&gt;
    v_start_pio   NUMBER;&lt;br /&gt;
    v_pio_ins     NUMBER;&lt;br /&gt;
    v_pio_sel     NUMBER;&lt;br /&gt;
    v_seg_bytes   NUMBER;&lt;br /&gt;
    v_actual_bytes NUMBER;&lt;br /&gt;
    v_frag_pct    NUMBER;&lt;br /&gt;
    v_sum_len     NUMBER;&lt;br /&gt;
    v_doc         CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_doc := RPAD(&#039;X&#039;, c_test_lob_size, &#039;X&#039;);&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(RPAD(&#039;CHUNK(byte)&#039;,12) || RPAD(&#039;INSERT(초)&#039;,12) ||&lt;br /&gt;
                          RPAD(&#039;SELECT(초)&#039;,12) || RPAD(&#039;물리IO(SEL)&#039;,12) ||&lt;br /&gt;
                          RPAD(&#039;세그먼트(MB)&#039;,14) || &#039;데이터대비 오버헤드(%)&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(RPAD(&#039;-&#039;,90,&#039;-&#039;));&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_chunks.COUNT LOOP&lt;br /&gt;
        -- (1) 초기화 + CHUNK 변경&lt;br /&gt;
        EXECUTE IMMEDIATE &#039;TRUNCATE TABLE CHUNK_TEST_TBL&#039;;&lt;br /&gt;
        EXECUTE IMMEDIATE&lt;br /&gt;
            &#039;ALTER TABLE CHUNK_TEST_TBL MOVE LOB (doc) STORE AS (CHUNK &#039; || v_chunks(i) || &#039;)&#039;;&lt;br /&gt;
&lt;br /&gt;
        -- (2) INSERT 성능 측정&lt;br /&gt;
        v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
        FOR r IN 1 .. c_row_count LOOP&lt;br /&gt;
            INSERT INTO CHUNK_TEST_TBL (id, doc) VALUES (r, v_doc);&lt;br /&gt;
        END LOOP;&lt;br /&gt;
        COMMIT;&lt;br /&gt;
        v_ins_sec := (DBMS_UTILITY.GET_TIME - v_start_time) / 100;&lt;br /&gt;
&lt;br /&gt;
        EXECUTE IMMEDIATE&lt;br /&gt;
            &#039;BEGIN DBMS_STATS.GATHER_TABLE_STATS(:o, :t, CASCADE =&amp;gt; TRUE); END;&#039;&lt;br /&gt;
            USING USER, &#039;CHUNK_TEST_TBL&#039;;&lt;br /&gt;
&lt;br /&gt;
        -- (3) SELECT(전체 읽기) 성능 측정&lt;br /&gt;
        v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
        v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
        SELECT SUM(DBMS_LOB.GETLENGTH(doc)) INTO v_sum_len FROM CHUNK_TEST_TBL;&lt;br /&gt;
        v_sel_sec := (DBMS_UTILITY.GET_TIME - v_start_time) / 100;&lt;br /&gt;
        v_pio_sel := GET_SESS_PIO - v_start_pio;&lt;br /&gt;
&lt;br /&gt;
        -- (4) 공간 사용량(세그먼트 크기) 및 오버헤드 비율&lt;br /&gt;
        SELECT bytes INTO v_seg_bytes&lt;br /&gt;
        FROM dba_segments&lt;br /&gt;
        WHERE owner = USER AND segment_name = &#039;CHUNK_TEST_LSEG&#039;;&lt;br /&gt;
&lt;br /&gt;
        v_actual_bytes := c_test_lob_size * c_row_count;&lt;br /&gt;
        v_frag_pct := ROUND((v_seg_bytes - v_actual_bytes) / v_actual_bytes * 100, 1);&lt;br /&gt;
&lt;br /&gt;
        DBMS_OUTPUT.PUT_LINE(&lt;br /&gt;
            RPAD(v_chunks(i), 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(v_ins_sec, &#039;999.99&#039;), 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(v_sel_sec, &#039;999.99&#039;), 12) ||&lt;br /&gt;
            RPAD(v_pio_sel, 12) ||&lt;br /&gt;
            RPAD(TO_CHAR(ROUND(v_seg_bytes/1024/1024, 2), &#039;99999.99&#039;), 14) ||&lt;br /&gt;
            TO_CHAR(v_frag_pct)&lt;br /&gt;
        );&lt;br /&gt;
    END LOOP;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 2. 결과 해석 가이드&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- - INSERT(초)      : CHUNK가 너무 작으면 청크 개수가 늘어 관리 오버헤드 증가,&lt;br /&gt;
--                      너무 크면 큰 단위 할당 비용으로 오히려 느려질 수 있음&lt;br /&gt;
-- - SELECT(초)/물리IO: CHUNK가 데이터 크기에 비해 작을수록 여러 청크를&lt;br /&gt;
--                      나눠 읽어 물리IO 횟수가 늘어나는 경향&lt;br /&gt;
-- - 오버헤드(%)      : (세그먼트 실제 크기 - 순수 데이터 크기) / 데이터 크기&lt;br /&gt;
--                      CHUNK가 데이터보다 훨씬 크면 이 값이 커짐(공간 낭비)&lt;br /&gt;
--                      예: 데이터 50KB인데 CHUNK 1MB면 매 LOB이 1MB를 점유&lt;br /&gt;
--&lt;br /&gt;
-- 최적점은 보통 &amp;quot;오버헤드(%)가 과도하게 커지기 직전이면서&lt;br /&gt;
-- SELECT 물리IO가 충분히 낮아지는 지점&amp;quot;입니다.&lt;br /&gt;
-- 아래처럼 여러 대표 크기(작음/중간/큼)로 각각 돌려서&lt;br /&gt;
-- 실제 운영 중 크기 분포에 맞는 값을 찾는 것을 권장합니다.&lt;br /&gt;
--   c_test_lob_size를 3번 조정해서(예: 2000, 50000, 500000) 재실행&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 3. 정리&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- DROP TABLE CHUNK_TEST_TBL PURGE;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_PIO;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Lob_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1828</id>
		<title>Lob 테스트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Lob_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1828"/>
		<updated>2026-09-15T03:05:34Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* LOB ENABLE STORAGE IN ROW 성능 비교 테스트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== LOB ENABLE STORAGE IN ROW 성능 비교 테스트 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================================&lt;br /&gt;
-- LOB ENABLE STORAGE IN ROW 성능 비교 테스트&lt;br /&gt;
-- 목적: 4000byte 이하(인라인) vs 4000byte 초과(아웃오브라인) 데이터를&lt;br /&gt;
--       삽입/조회할 때 성능(시간, 논리/물리 I/O, 공간 사용량) 차이를 측정&lt;br /&gt;
-- 구성: 하나의 테이블에 LOB 컬럼 2개(DOC_A, DOC_B)를 두어,&lt;br /&gt;
--       컬럼별로 다른 CHUNK/FREEPOOLS 설정을 줘도 비교할 수 있게 함&lt;br /&gt;
-- 실행: sqlplus 계정/비번@dsn @lob_inrow_perf_test.sql&lt;br /&gt;
-- ============================================================&lt;br /&gt;
&lt;br /&gt;
SET SERVEROUTPUT ON SIZE UNLIMITED&lt;br /&gt;
SET TIMING ON&lt;br /&gt;
SET LINESIZE 200&lt;br /&gt;
SET PAGESIZE 100&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 0. 기존 오브젝트 정리 (재실행 대비)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
BEGIN&lt;br /&gt;
    EXECUTE IMMEDIATE &#039;DROP TABLE PERF_TEST_LOB2 PURGE&#039;;&lt;br /&gt;
EXCEPTION&lt;br /&gt;
    WHEN OTHERS THEN&lt;br /&gt;
        IF SQLCODE != -942 THEN RAISE; END IF;  -- ORA-00942: 테이블 없음은 무시&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 1. 테스트 테이블 생성 (LOB 컬럼 2개, ENABLE STORAGE IN ROW)&lt;br /&gt;
--    DOC_A / DOC_B에 CHUNK를 다르게 줘서 컬럼별 영향도 비교도 가능&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE TABLE PERF_TEST_LOB2 (&lt;br /&gt;
    id           NUMBER          NOT NULL,&lt;br /&gt;
    size_group   VARCHAR2(10)    NOT NULL,   -- &#039;SMALL&#039; (&amp;lt;=4000B) / &#039;LARGE&#039; (&amp;gt;4000B)&lt;br /&gt;
    created_date DATE            DEFAULT SYSDATE,&lt;br /&gt;
    doc_a        CLOB,&lt;br /&gt;
    doc_b        CLOB,&lt;br /&gt;
    CONSTRAINT pk_perf_test_lob2 PRIMARY KEY (id)&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_a) STORE AS SECUREFILE doc_a_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_b) STORE AS SECUREFILE doc_b_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 2. 세션 I/O 통계 측정용 헬퍼 프로시저&lt;br /&gt;
--    (V$SESSTAT 기반으로 논리적/물리적 읽기 변화량을 계산)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE OR REPLACE PROCEDURE PRINT_SESS_IO_DELTA (&lt;br /&gt;
    p_label     IN VARCHAR2,&lt;br /&gt;
    p_start_lio IN NUMBER,&lt;br /&gt;
    p_start_pio IN NUMBER&lt;br /&gt;
) IS&lt;br /&gt;
    v_lio NUMBER;&lt;br /&gt;
    v_pio NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v_lio&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;session logical reads&#039;;&lt;br /&gt;
&lt;br /&gt;
    SELECT ss.value INTO v_pio&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&lt;br /&gt;
        RPAD(p_label, 28) ||&lt;br /&gt;
        &#039; logical_reads(delta)=&#039; || LPAD(v_lio - p_start_lio, 10) ||&lt;br /&gt;
        &#039;  physical_reads(delta)=&#039; || LPAD(v_pio - p_start_pio, 10)&lt;br /&gt;
    );&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_LIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;session logical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_PIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 3. 테스트 1: SMALL 그룹 삽입 (각 LOB 3900byte, 4000byte 미만 -&amp;gt; 인라인)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time   NUMBER;&lt;br /&gt;
    v_start_lio    NUMBER;&lt;br /&gt;
    v_start_pio    NUMBER;&lt;br /&gt;
    v_row_count    PLS_INTEGER := 2000;   -- 필요에 따라 조정&lt;br /&gt;
    v_small_text   CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_small_text := RPAD(&#039;A&#039;, 3900, &#039;A&#039;);   -- 3900byte, 4000byte 임계치 이하&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        INSERT INTO PERF_TEST_LOB2 (id, size_group, doc_a, doc_b)&lt;br /&gt;
        VALUES (i, &#039;SMALL&#039;, v_small_text, v_small_text);&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [SMALL] &#039; || v_row_count || &#039;건 INSERT ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;SMALL INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 4. 테스트 2: LARGE 그룹 삽입 (각 LOB 8000byte, 4000byte 초과 -&amp;gt; 아웃오브라인)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time   NUMBER;&lt;br /&gt;
    v_start_lio    NUMBER;&lt;br /&gt;
    v_start_pio    NUMBER;&lt;br /&gt;
    v_row_count    PLS_INTEGER := 2000;&lt;br /&gt;
    v_large_text   CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_large_text := RPAD(&#039;B&#039;, 8000, &#039;B&#039;);   -- 8000byte, 4000byte 임계치 초과&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        INSERT INTO PERF_TEST_LOB2 (id, size_group, doc_a, doc_b)&lt;br /&gt;
        VALUES (2000 + i, &#039;LARGE&#039;, v_large_text, v_large_text);&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [LARGE] &#039; || v_row_count || &#039;건 INSERT ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;LARGE INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 통계 최신화 (조회 테스트 전 필수)&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, &#039;PERF_TEST_LOB2&#039;, CASCADE =&amp;gt; TRUE);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 5. 조회 성능 비교: SMALL 그룹 vs LARGE 그룹 (LOB 길이 합산으로 실제 LOB 접근 유도)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time NUMBER;&lt;br /&gt;
    v_start_lio  NUMBER;&lt;br /&gt;
    v_start_pio  NUMBER;&lt;br /&gt;
    v_sum_len    NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    -- SMALL 그룹 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_a) + DBMS_LOB.GETLENGTH(doc_b))&lt;br /&gt;
    INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_LOB2&lt;br /&gt;
    WHERE size_group = &#039;SMALL&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [SMALL] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;SMALL SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
&lt;br /&gt;
    -- LARGE 그룹 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_a) + DBMS_LOB.GETLENGTH(doc_b))&lt;br /&gt;
    INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_LOB2&lt;br /&gt;
    WHERE size_group = &#039;LARGE&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [LARGE] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;LARGE SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 6. 실제 인라인/아웃오브라인 여부 확인 (LOB 세그먼트 공간 사용량 기준)&lt;br /&gt;
--    -&amp;gt; 인라인 저장분은 LOB 세그먼트를 거의 소비하지 않고,&lt;br /&gt;
--       아웃오브라인 저장분은 LOB 세그먼트 공간을 그만큼 소비함&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
COLUMN segment_name FORMAT A20&lt;br /&gt;
COLUMN mb FORMAT 999,999.99&lt;br /&gt;
&lt;br /&gt;
SELECT ds.segment_name, ds.segment_type, ROUND(ds.bytes/1024/1024, 2) AS mb&lt;br /&gt;
FROM dba_segments ds&lt;br /&gt;
WHERE ds.owner = USER&lt;br /&gt;
  AND ds.segment_name IN (&lt;br /&gt;
        SELECT segment_name FROM dba_lobs&lt;br /&gt;
        WHERE owner = USER AND table_name = &#039;PERF_TEST_LOB2&#039;&lt;br /&gt;
      )&lt;br /&gt;
ORDER BY ds.segment_name;&lt;br /&gt;
&lt;br /&gt;
-- LOB 세그먼트 상세 설정 확인&lt;br /&gt;
SELECT column_name, segment_name, chunk, in_row, securefile, cache&lt;br /&gt;
FROM dba_lobs&lt;br /&gt;
WHERE owner = USER AND table_name = &#039;PERF_TEST_LOB2&#039;;&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 7. (선택) FREEPOOLS/CHUNK 값을 바꿔가며 재테스트하고 싶을 때&lt;br /&gt;
--    아래처럼 MOVE로 컬럼별 설정을 바꾼 뒤 3~6번을 재실행해서 비교&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- ALTER TABLE PERF_TEST_LOB2 MOVE LOB (doc_a) STORE AS (CHUNK 32768 FREEPOOLS 4);&lt;br /&gt;
-- ALTER TABLE PERF_TEST_LOB2 MOVE LOB (doc_b) STORE AS (CHUNK 32768 FREEPOOLS 4);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 8. 정리 (재테스트 전 초기화하고 싶을 때)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- TRUNCATE TABLE PERF_TEST_LOB2;&lt;br /&gt;
-- DROP TABLE PERF_TEST_LOB2 PURGE;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_LIO;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_PIO;&lt;br /&gt;
-- DROP PROCEDURE PRINT_SESS_IO_DELTA;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== storage in row 옵션 성능 개선 테스트 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================================&lt;br /&gt;
-- ENABLE STORAGE IN ROW vs DISABLE STORAGE IN ROW 성능 비교 테스트&lt;br /&gt;
-- 목적: &amp;quot;작은 크기(4000byte 이하) LOB&amp;quot;을 저장할 때&lt;br /&gt;
--       ENABLE STORAGE IN ROW(인라인 허용)와&lt;br /&gt;
--       DISABLE STORAGE IN ROW(항상 LOB세그먼트로 분리)의&lt;br /&gt;
--       INSERT/SELECT 성능, I/O, 공간 사용량 차이를 측정&lt;br /&gt;
-- 구성: 한 테이블에 LOB 컬럼 2개&lt;br /&gt;
--       DOC_INROW  -&amp;gt; ENABLE STORAGE IN ROW  (옵션 켬)&lt;br /&gt;
--       DOC_OUTROW -&amp;gt; DISABLE STORAGE IN ROW (옵션 끔, 항상 아웃오브라인)&lt;br /&gt;
--       두 컬럼에 &amp;quot;완전히 동일한 크기의 작은 데이터&amp;quot;를 넣어 공정 비교&lt;br /&gt;
-- 실행: sqlplus 계정/비번@dsn @lob_inrow_option_test.sql&lt;br /&gt;
-- ============================================================&lt;br /&gt;
&lt;br /&gt;
SET SERVEROUTPUT ON SIZE UNLIMITED&lt;br /&gt;
SET TIMING ON&lt;br /&gt;
SET LINESIZE 200&lt;br /&gt;
SET PAGESIZE 100&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 0. 기존 오브젝트 정리 (재실행 대비)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
BEGIN&lt;br /&gt;
    EXECUTE IMMEDIATE &#039;DROP TABLE PERF_TEST_INROW PURGE&#039;;&lt;br /&gt;
EXCEPTION&lt;br /&gt;
    WHEN OTHERS THEN&lt;br /&gt;
        IF SQLCODE != -942 THEN RAISE; END IF;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 1. 테스트 테이블 생성&lt;br /&gt;
--    DOC_INROW  : ENABLE STORAGE IN ROW  (기본값, 작은 값은 행에 인라인 저장)&lt;br /&gt;
--    DOC_OUTROW : DISABLE STORAGE IN ROW (항상 별도 LOB세그먼트에 저장)&lt;br /&gt;
--    나머지 옵션(CHUNK 등)은 동일하게 맞춰서 옵션 하나만의 차이를 봄&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE TABLE PERF_TEST_INROW (&lt;br /&gt;
    id           NUMBER          NOT NULL,&lt;br /&gt;
    created_date DATE            DEFAULT SYSDATE,&lt;br /&gt;
    doc_inrow    CLOB,&lt;br /&gt;
    doc_outrow   CLOB,&lt;br /&gt;
    CONSTRAINT pk_perf_test_inrow PRIMARY KEY (id)&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_inrow) STORE AS SECUREFILE inrow_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_outrow) STORE AS SECUREFILE outrow_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    DISABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 2. 세션 I/O 측정 헬퍼 함수 (이미 있다면 재생성됨)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_LIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;session logical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_PIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE PROCEDURE PRINT_SESS_IO_DELTA (&lt;br /&gt;
    p_label     IN VARCHAR2,&lt;br /&gt;
    p_start_lio IN NUMBER,&lt;br /&gt;
    p_start_pio IN NUMBER&lt;br /&gt;
) IS&lt;br /&gt;
    v_lio NUMBER := GET_SESS_LIO;&lt;br /&gt;
    v_pio NUMBER := GET_SESS_PIO;&lt;br /&gt;
BEGIN&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&lt;br /&gt;
        RPAD(p_label, 28) ||&lt;br /&gt;
        &#039; logical_reads(delta)=&#039; || LPAD(v_lio - p_start_lio, 10) ||&lt;br /&gt;
        &#039;  physical_reads(delta)=&#039; || LPAD(v_pio - p_start_pio, 10)&lt;br /&gt;
    );&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 3. 테스트 1: DOC_INROW 컬럼에 작은 값 INSERT (4000byte 이하 -&amp;gt; 인라인 저장)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time NUMBER;&lt;br /&gt;
    v_start_lio  NUMBER;&lt;br /&gt;
    v_start_pio  NUMBER;&lt;br /&gt;
    v_row_count  PLS_INTEGER := 5000;&lt;br /&gt;
    v_small_text CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_small_text := RPAD(&#039;A&#039;, 500, &#039;A&#039;);   -- 500byte, 동일 크기로 공정 비교&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        INSERT INTO PERF_TEST_INROW (id, doc_inrow)&lt;br /&gt;
        VALUES (i, v_small_text);&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [DOC_INROW] &#039; || v_row_count || &#039;건 INSERT (ENABLE STORAGE IN ROW) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;INROW INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 4. 테스트 2: DOC_OUTROW 컬럼에 &amp;quot;완전히 동일한&amp;quot; 작은 값 INSERT&lt;br /&gt;
--    (DISABLE STORAGE IN ROW이므로 크기와 무관하게 항상 아웃오브라인)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time NUMBER;&lt;br /&gt;
    v_start_lio  NUMBER;&lt;br /&gt;
    v_start_pio  NUMBER;&lt;br /&gt;
    v_row_count  PLS_INTEGER := 5000;&lt;br /&gt;
    v_small_text CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_small_text := RPAD(&#039;A&#039;, 500, &#039;A&#039;);   -- 위와 동일한 500byte&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        UPDATE PERF_TEST_INROW&lt;br /&gt;
        SET doc_outrow = v_small_text&lt;br /&gt;
        WHERE id = i;&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [DOC_OUTROW] &#039; || v_row_count || &#039;건 UPDATE (DISABLE STORAGE IN ROW) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;OUTROW INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 통계 최신화 (조회 테스트 전 필수)&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, &#039;PERF_TEST_INROW&#039;, CASCADE =&amp;gt; TRUE);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 5. 조회 성능 비교: 같은 크기(500byte)인데 저장 방식만 다른 두 컬럼&lt;br /&gt;
--    DBMS_LOB.GETLENGTH로 실제 LOB 값을 건드리는 조회를 유도&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time NUMBER;&lt;br /&gt;
    v_start_lio  NUMBER;&lt;br /&gt;
    v_start_pio  NUMBER;&lt;br /&gt;
    v_sum_len    NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    -- DOC_INROW 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_inrow)) INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_INROW;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [DOC_INROW] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;INROW SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
&lt;br /&gt;
    -- DOC_OUTROW 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_outrow)) INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_INROW;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [DOC_OUTROW] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;OUTROW SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 6. 핵심 검증: LOB 세그먼트 공간 사용량 비교&lt;br /&gt;
--    -&amp;gt; 같은 크기(500byte)인데도 DISABLE STORAGE IN ROW는&lt;br /&gt;
--       LOB 세그먼트 공간을 그만큼 소비하고,&lt;br /&gt;
--       ENABLE STORAGE IN ROW는 거의 소비하지 않아야 정상&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
COLUMN segment_name FORMAT A20&lt;br /&gt;
COLUMN mb FORMAT 999,999.99&lt;br /&gt;
&lt;br /&gt;
SELECT ds.segment_name, ROUND(ds.bytes/1024/1024, 2) AS mb&lt;br /&gt;
FROM dba_segments ds&lt;br /&gt;
WHERE ds.owner = USER&lt;br /&gt;
  AND ds.segment_name IN (&#039;INROW_LSEG&#039;, &#039;OUTROW_LSEG&#039;)&lt;br /&gt;
ORDER BY ds.segment_name;&lt;br /&gt;
&lt;br /&gt;
-- 컬럼별 IN_ROW 설정 및 실제 LOB 세그먼트 정보 확인&lt;br /&gt;
SELECT column_name, segment_name, in_row, securefile, chunk&lt;br /&gt;
FROM dba_lobs&lt;br /&gt;
WHERE owner = USER AND table_name = &#039;PERF_TEST_INROW&#039;;&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 7. 결과 해석 가이드&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- - INROW_LSEG 의 MB가 OUTROW_LSEG 대비 현저히 작다면&lt;br /&gt;
--   (거의 0에 가깝다면) ENABLE STORAGE IN ROW가 정상 동작 중인 것&lt;br /&gt;
-- - DOC_INROW SELECT의 physical_reads(delta)가 DOC_OUTROW SELECT보다&lt;br /&gt;
--   작게 나오면, 인라인 저장이 실제로 I/O를 줄여주고 있다는 증거&lt;br /&gt;
-- - 두 컬럼의 physical_reads가 비슷하다면 OS/버퍼캐시에 이미&lt;br /&gt;
--   캐싱된 상태일 수 있으므로, 재테스트 전 아래로 캐시를 비우고 확인&lt;br /&gt;
--   ALTER SYSTEM FLUSH BUFFER_CACHE;   -- 테스트/개발 환경에서만 사용&lt;br /&gt;
--&lt;br /&gt;
-- 5000byte 등 4000byte를 &amp;quot;초과&amp;quot;하는 값으로 위 3~4번을 다시 돌려보면&lt;br /&gt;
-- ENABLE STORAGE IN ROW라도 자동으로 아웃오브라인 전환되어&lt;br /&gt;
-- DOC_INROW와 DOC_OUTROW의 결과가 비슷해지는 것도 확인할 수 있음&lt;br /&gt;
-- (옵션의 의미: &amp;quot;작을 때만&amp;quot; 인라인을 &amp;quot;허용&amp;quot;하는 것이지 강제하는 게 아님)&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 8. 정리&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- DROP TABLE PERF_TEST_INROW PURGE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=Lob_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1827</id>
		<title>Lob 테스트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=Lob_%ED%85%8C%EC%8A%A4%ED%8A%B8&amp;diff=1827"/>
		<updated>2026-09-15T00:35:54Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: === LOB ENABLE STORAGE IN ROW 성능 비교 테스트 === &amp;lt;source lang=sql&amp;gt; -- ============================================================ -- LOB ENABLE STORAGE IN ROW 성능 비교 테스트 -- 목적: 4000byte 이하(인라인) vs 4000byte 초과(아웃오브라인) 데이터를 --       삽입/조회할 때 성능(시간, 논리/물리 I/O, 공간 사용량) 차이를 측정 -- 구성: 하나의 테이블에 LOB 컬럼 2개(DOC_A, DOC_B)를 두어, --       컬럼별로 다...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== LOB ENABLE STORAGE IN ROW 성능 비교 테스트 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================================&lt;br /&gt;
-- LOB ENABLE STORAGE IN ROW 성능 비교 테스트&lt;br /&gt;
-- 목적: 4000byte 이하(인라인) vs 4000byte 초과(아웃오브라인) 데이터를&lt;br /&gt;
--       삽입/조회할 때 성능(시간, 논리/물리 I/O, 공간 사용량) 차이를 측정&lt;br /&gt;
-- 구성: 하나의 테이블에 LOB 컬럼 2개(DOC_A, DOC_B)를 두어,&lt;br /&gt;
--       컬럼별로 다른 CHUNK/FREEPOOLS 설정을 줘도 비교할 수 있게 함&lt;br /&gt;
-- 실행: sqlplus 계정/비번@dsn @lob_inrow_perf_test.sql&lt;br /&gt;
-- ============================================================&lt;br /&gt;
&lt;br /&gt;
SET SERVEROUTPUT ON SIZE UNLIMITED&lt;br /&gt;
SET TIMING ON&lt;br /&gt;
SET LINESIZE 200&lt;br /&gt;
SET PAGESIZE 100&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 0. 기존 오브젝트 정리 (재실행 대비)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
BEGIN&lt;br /&gt;
    EXECUTE IMMEDIATE &#039;DROP TABLE PERF_TEST_LOB2 PURGE&#039;;&lt;br /&gt;
EXCEPTION&lt;br /&gt;
    WHEN OTHERS THEN&lt;br /&gt;
        IF SQLCODE != -942 THEN RAISE; END IF;  -- ORA-00942: 테이블 없음은 무시&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 1. 테스트 테이블 생성 (LOB 컬럼 2개, ENABLE STORAGE IN ROW)&lt;br /&gt;
--    DOC_A / DOC_B에 CHUNK를 다르게 줘서 컬럼별 영향도 비교도 가능&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE TABLE PERF_TEST_LOB2 (&lt;br /&gt;
    id           NUMBER          NOT NULL,&lt;br /&gt;
    size_group   VARCHAR2(10)    NOT NULL,   -- &#039;SMALL&#039; (&amp;lt;=4000B) / &#039;LARGE&#039; (&amp;gt;4000B)&lt;br /&gt;
    created_date DATE            DEFAULT SYSDATE,&lt;br /&gt;
    doc_a        CLOB,&lt;br /&gt;
    doc_b        CLOB,&lt;br /&gt;
    CONSTRAINT pk_perf_test_lob2 PRIMARY KEY (id)&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_a) STORE AS SECUREFILE doc_a_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
)&lt;br /&gt;
LOB (doc_b) STORE AS SECUREFILE doc_b_lseg (&lt;br /&gt;
    TABLESPACE users&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    NOCACHE&lt;br /&gt;
    NOLOGGING&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 2. 세션 I/O 통계 측정용 헬퍼 프로시저&lt;br /&gt;
--    (V$SESSTAT 기반으로 논리적/물리적 읽기 변화량을 계산)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
CREATE OR REPLACE PROCEDURE PRINT_SESS_IO_DELTA (&lt;br /&gt;
    p_label     IN VARCHAR2,&lt;br /&gt;
    p_start_lio IN NUMBER,&lt;br /&gt;
    p_start_pio IN NUMBER&lt;br /&gt;
) IS&lt;br /&gt;
    v_lio NUMBER;&lt;br /&gt;
    v_pio NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v_lio&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;session logical reads&#039;;&lt;br /&gt;
&lt;br /&gt;
    SELECT ss.value INTO v_pio&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&lt;br /&gt;
        RPAD(p_label, 28) ||&lt;br /&gt;
        &#039; logical_reads(delta)=&#039; || LPAD(v_lio - p_start_lio, 10) ||&lt;br /&gt;
        &#039;  physical_reads(delta)=&#039; || LPAD(v_pio - p_start_pio, 10)&lt;br /&gt;
    );&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_LIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;session logical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
CREATE OR REPLACE FUNCTION GET_SESS_PIO RETURN NUMBER IS&lt;br /&gt;
    v NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT ss.value INTO v&lt;br /&gt;
    FROM v$sesstat ss, v$statname sn&lt;br /&gt;
    WHERE ss.sid = SYS_CONTEXT(&#039;USERENV&#039;,&#039;SID&#039;)&lt;br /&gt;
      AND ss.statistic# = sn.statistic#&lt;br /&gt;
      AND sn.name = &#039;physical reads&#039;;&lt;br /&gt;
    RETURN v;&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 3. 테스트 1: SMALL 그룹 삽입 (각 LOB 3900byte, 4000byte 미만 -&amp;gt; 인라인)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time   NUMBER;&lt;br /&gt;
    v_start_lio    NUMBER;&lt;br /&gt;
    v_start_pio    NUMBER;&lt;br /&gt;
    v_row_count    PLS_INTEGER := 2000;   -- 필요에 따라 조정&lt;br /&gt;
    v_small_text   CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_small_text := RPAD(&#039;A&#039;, 3900, &#039;A&#039;);   -- 3900byte, 4000byte 임계치 이하&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        INSERT INTO PERF_TEST_LOB2 (id, size_group, doc_a, doc_b)&lt;br /&gt;
        VALUES (i, &#039;SMALL&#039;, v_small_text, v_small_text);&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [SMALL] &#039; || v_row_count || &#039;건 INSERT ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;SMALL INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 4. 테스트 2: LARGE 그룹 삽입 (각 LOB 8000byte, 4000byte 초과 -&amp;gt; 아웃오브라인)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time   NUMBER;&lt;br /&gt;
    v_start_lio    NUMBER;&lt;br /&gt;
    v_start_pio    NUMBER;&lt;br /&gt;
    v_row_count    PLS_INTEGER := 2000;&lt;br /&gt;
    v_large_text   CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    v_large_text := RPAD(&#039;B&#039;, 8000, &#039;B&#039;);   -- 8000byte, 4000byte 임계치 초과&lt;br /&gt;
&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    FOR i IN 1 .. v_row_count LOOP&lt;br /&gt;
        INSERT INTO PERF_TEST_LOB2 (id, size_group, doc_a, doc_b)&lt;br /&gt;
        VALUES (2000 + i, &#039;LARGE&#039;, v_large_text, v_large_text);&lt;br /&gt;
    END LOOP;&lt;br /&gt;
    COMMIT;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [LARGE] &#039; || v_row_count || &#039;건 INSERT ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;LARGE INSERT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 통계 최신화 (조회 테스트 전 필수)&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, &#039;PERF_TEST_LOB2&#039;, CASCADE =&amp;gt; TRUE);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 5. 조회 성능 비교: SMALL 그룹 vs LARGE 그룹 (LOB 길이 합산으로 실제 LOB 접근 유도)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
DECLARE&lt;br /&gt;
    v_start_time NUMBER;&lt;br /&gt;
    v_start_lio  NUMBER;&lt;br /&gt;
    v_start_pio  NUMBER;&lt;br /&gt;
    v_sum_len    NUMBER;&lt;br /&gt;
BEGIN&lt;br /&gt;
    -- SMALL 그룹 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_a) + DBMS_LOB.GETLENGTH(doc_b))&lt;br /&gt;
    INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_LOB2&lt;br /&gt;
    WHERE size_group = &#039;SMALL&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [SMALL] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;SMALL SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
&lt;br /&gt;
    -- LARGE 그룹 조회&lt;br /&gt;
    v_start_time := DBMS_UTILITY.GET_TIME;&lt;br /&gt;
    v_start_lio  := GET_SESS_LIO;&lt;br /&gt;
    v_start_pio  := GET_SESS_PIO;&lt;br /&gt;
&lt;br /&gt;
    SELECT SUM(DBMS_LOB.GETLENGTH(doc_a) + DBMS_LOB.GETLENGTH(doc_b))&lt;br /&gt;
    INTO v_sum_len&lt;br /&gt;
    FROM PERF_TEST_LOB2&lt;br /&gt;
    WHERE size_group = &#039;LARGE&#039;;&lt;br /&gt;
&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;=== [LARGE] 전체 조회 (sum_len=&#039; || v_sum_len || &#039;) ===&#039;);&lt;br /&gt;
    DBMS_OUTPUT.PUT_LINE(&#039;경과시간(centisec): &#039; || (DBMS_UTILITY.GET_TIME - v_start_time));&lt;br /&gt;
    PRINT_SESS_IO_DELTA(&#039;LARGE SELECT I/O&#039;, v_start_lio, v_start_pio);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 6. 실제 인라인/아웃오브라인 여부 확인 (LOB 세그먼트 공간 사용량 기준)&lt;br /&gt;
--    -&amp;gt; 인라인 저장분은 LOB 세그먼트를 거의 소비하지 않고,&lt;br /&gt;
--       아웃오브라인 저장분은 LOB 세그먼트 공간을 그만큼 소비함&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
COLUMN segment_name FORMAT A20&lt;br /&gt;
COLUMN mb FORMAT 999,999.99&lt;br /&gt;
&lt;br /&gt;
SELECT ds.segment_name, ds.segment_type, ROUND(ds.bytes/1024/1024, 2) AS mb&lt;br /&gt;
FROM dba_segments ds&lt;br /&gt;
WHERE ds.owner = USER&lt;br /&gt;
  AND ds.segment_name IN (&lt;br /&gt;
        SELECT segment_name FROM dba_lobs&lt;br /&gt;
        WHERE owner = USER AND table_name = &#039;PERF_TEST_LOB2&#039;&lt;br /&gt;
      )&lt;br /&gt;
ORDER BY ds.segment_name;&lt;br /&gt;
&lt;br /&gt;
-- LOB 세그먼트 상세 설정 확인&lt;br /&gt;
SELECT column_name, segment_name, chunk, in_row, securefile, cache&lt;br /&gt;
FROM dba_lobs&lt;br /&gt;
WHERE owner = USER AND table_name = &#039;PERF_TEST_LOB2&#039;;&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 7. (선택) FREEPOOLS/CHUNK 값을 바꿔가며 재테스트하고 싶을 때&lt;br /&gt;
--    아래처럼 MOVE로 컬럼별 설정을 바꾼 뒤 3~6번을 재실행해서 비교&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- ALTER TABLE PERF_TEST_LOB2 MOVE LOB (doc_a) STORE AS (CHUNK 32768 FREEPOOLS 4);&lt;br /&gt;
-- ALTER TABLE PERF_TEST_LOB2 MOVE LOB (doc_b) STORE AS (CHUNK 32768 FREEPOOLS 4);&lt;br /&gt;
&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- 8. 정리 (재테스트 전 초기화하고 싶을 때)&lt;br /&gt;
-- ------------------------------------------------------------&lt;br /&gt;
-- TRUNCATE TABLE PERF_TEST_LOB2;&lt;br /&gt;
-- DROP TABLE PERF_TEST_LOB2 PURGE;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_LIO;&lt;br /&gt;
-- DROP FUNCTION GET_SESS_PIO;&lt;br /&gt;
-- DROP PROCEDURE PRINT_SESS_IO_DELTA;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1826</id>
		<title>오라클 GCS 와 GES</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1826"/>
		<updated>2026-09-14T12:21:17Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== GCS(Global Cache Service)와 GES(Global Enqueue Service)==&lt;br /&gt;
* Oracle RAC의 핵심 메커니즘인 GCS(Global Cache Service)와 GES(Global Enqueue Service)는 여러 인스턴스가 하나의 데이터베이스를 동시에 접근할 때 **데이터 일관성**과 **자원 동기화**를 보장하는 두 축입니다.&lt;br /&gt;
&lt;br /&gt;
=== GCS (Global Cache Service) ===&lt;br /&gt;
::: — 캐시 퓨전(Cache Fusion)의 핵심&lt;br /&gt;
:여러 인스턴스의 버퍼캐시에 흩어져 있는 **동일 데이터 블록의 일관성**을 인스턴스 간 네트워크(인터커넥트)를 통해 관리합니다. &lt;br /&gt;
:::디스크를 거치지 않고 메모리-투-메모리로 블록을 주고받는 것이 핵심입니다.&lt;br /&gt;
&lt;br /&gt;
* 핵심 개념&lt;br /&gt;
:- Cache Fusion: 한 인스턴스가 수정한 블록을 다른 인스턴스가 요청하면, 디스크에 쓰지 않고 인터커넥트를 통해 블록을 직접 전송합니다.&lt;br /&gt;
&lt;br /&gt;
:- 자원 마스터링(Resource Mastering): 각 블록(정확히는 자원 단위)마다 어느 인스턴스가 &amp;quot;마스터&amp;quot;인지가 정해져 있고, 마스터 인스턴스가 해당 블록의 상태(누가 갖고 있는지, 어떤 모드인지)를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
:- 블록 상태(Role/Mode):&lt;br /&gt;
:: - **Role**: Local(단일 인스턴스만 사용 중) / Global(여러 인스턴스가 공유 중)&lt;br /&gt;
:: - **Mode**: NULL(공유 안 함), SHARED(읽기 공유), EXCLUSIVE(단독 수정)&lt;br /&gt;
&lt;br /&gt;
==== 동작 흐름 예시 ====&lt;br /&gt;
# Instance A가 블록을 수정하려고 함 → GCS에 EXCLUSIVE 권한 요청&lt;br /&gt;
# GCS 마스터가 &amp;quot;Instance B가 이미 이 블록을 갖고 있다&amp;quot;는 걸 확인&lt;br /&gt;
# B의 버퍼에서 A로 **직접 전송**(Cache Fusion) — 이때 상황에 따라 CR(Consistent Read) 이미지 또는 Current 블록 전송&lt;br /&gt;
# A가 수정 완료 후, 필요시 다시 다른 인스턴스 요청에 따라 전송 지속&lt;br /&gt;
&lt;br /&gt;
==== 관련 대기 이벤트 (성능 진단 시 자주 봄) ====&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `gc cr request` | 다른 인스턴스에 Consistent Read 블록 요청 후 대기 |&lt;br /&gt;
| `gc current request` | 다른 인스턴스에 Current 블록(수정용) 요청 후 대기 |&lt;br /&gt;
| `gc buffer busy acquire/release` | 로컬에서 블록을 이미 누가 가져오는 중이라 대기 |&lt;br /&gt;
| `gc cr/current block 2-way`, `3-way` | 2-way는 요청자↔소유자 직접, 3-way는 마스터를 거쳐 전달(인터커넥트 홉이 하나 더 생김 → 더 느림) |&lt;br /&gt;
&lt;br /&gt;
인터커넥트가 느리거나(네트워크 지연, private interconnect 대역폭 부족), 특정 블록에 여러 인스턴스가 동시에 몰리는 **Hot Block** 상황(자주 갱신되는 소수 로우, 시퀀스 없는 카운터 컬럼 등)이면 `gc` 대기가 급증합니다.&lt;br /&gt;
&lt;br /&gt;
=== GES (Global Enqueue Service) ===&lt;br /&gt;
— 자원 잠금 동기화&lt;br /&gt;
&lt;br /&gt;
GCS가 **데이터 블록** 자체를 다룬다면, GES는 그보다 더 넓은 범위의 **논리적 자원(enqueue)**에 대한 인스턴스 간 잠금 동기화를 담당합니다. 즉 &amp;quot;블록의 내용&amp;quot;이 아니라 &amp;quot;누가 무엇을 잠갔는지&amp;quot;를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
==== GES가 관리하는 대표적 자원 ====&lt;br /&gt;
::::- **TX (Transaction lock)**: 로우 레벨 락 — 여러 인스턴스에서 같은 로우를 수정하려 할 때 조율&lt;br /&gt;
::::- **TM (DML enqueue)**: 테이블 레벨 락 — DDL/DML 충돌 방지&lt;br /&gt;
::::- **각종 딕셔너리 캐시 락(dc_*)**: 데이터 딕셔너리 메타데이터 동기화&lt;br /&gt;
::::- **라이브러리 캐시 락(library cache lock, library cache pin)**: SQL/PL·SQL 커서, 오브젝트 정의 동기화&lt;br /&gt;
::::- **Sequence enqueue (SQ)**: 시퀀스 캐시 동기화 (NOORDER/캐시 크기에 따라 경합 발생 가능)&lt;br /&gt;
&lt;br /&gt;
**관련 대기 이벤트**&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `enq: TX - row lock contention` | 여러 세션(다른 인스턴스 포함)이 같은 로우를 잠그려 대기 |&lt;br /&gt;
| `enq: TM - contention` | 테이블 락 경합(FK 인덱스 없음 등이 원인인 경우 많음) |&lt;br /&gt;
| `enq: HW - contention` | High Water Mark 확장 경합 — 여러 인스턴스에서 동시 INSERT로 세그먼트 확장할 때 |&lt;br /&gt;
| `enq: SQ - contention` | 시퀀스 NEXTVAL 요청 경합 — 캐시 크기가 작거나 NOORDER 미설정 시 |&lt;br /&gt;
| `row cache lock` | 딕셔너리 캐시 자원 경합 |&lt;br /&gt;
&lt;br /&gt;
## GCS vs GES 핵심 차이&lt;br /&gt;
&lt;br /&gt;
| 구분 | GCS | GES |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 관리 대상 | 데이터 블록(버퍼캐시의 실제 내용) | 논리적 자원/락(TX, TM, dc_*, library cache 등) |&lt;br /&gt;
| 목적 | 블록 데이터의 인스턴스 간 일관성 유지 | 자원 접근 순서/배타성 보장 |&lt;br /&gt;
| 핵심 메커니즘 | Cache Fusion (메모리 간 직접 전송) | Enqueue 획득/대기/해제 프로토콜 |&lt;br /&gt;
| 진단 뷰 | `V$GC_ELEMENT`, `GV$CACHE_TRANSFER`, `GV$BH` | `V$GES_ENQUEUE`, `GV$LOCK`, `GV$GES_RESOURCE` |&lt;br /&gt;
| 프로세스 | LMS(Lock Manager Server) 프로세스가 실무 담당 | LMD(Lock Manager Daemon)가 enqueue 요청 처리, LMON이 전체 조율 |&lt;br /&gt;
&lt;br /&gt;
두 서비스 모두 **LMON, LMD, LMS** 백그라운드 프로세스가 협력해서 동작합니다:&lt;br /&gt;
- **LMON**: Global Enqueue Service Monitor — 클러스터 재구성(노드 추가/제거), 장애 감지 시 리마스터링 주도&lt;br /&gt;
- **LMD**: Global Enqueue Service Daemon — enqueue 요청/데드락 감지 처리&lt;br /&gt;
- **LMS**: Global Cache Service Process — 실제 블록 전송(Cache Fusion) 수행, 개수는 CPU 코어 수에 비례해 자동 설정&lt;br /&gt;
&lt;br /&gt;
=== 실무에서 자주 마주치는 경합 패턴 ===&lt;br /&gt;
::: ① Hot Block 경합**: 순번 발급용 단일 로우를 여러 인스턴스에서 동시에 UPDATE하는 설계(카운터 테이블 등) → `gc buffer busy`/`enq: TX`가 폭증. 해결은 시퀀스 사용, 또는 파티셔닝으로 인스턴스별 분산.&lt;br /&gt;
&lt;br /&gt;
::: ② 시퀀스 경합**: `NOCACHE` 또는 `ORDER` 옵션 시퀀스를 RAC에서 사용하면 매번 GES를 거쳐 전역 순서를 보장해야 해서 경합 심함 → 순서 보장이 꼭 필요한 게 아니면 `CACHE` 크게 잡고 `NOORDER` 사용 권장.&lt;br /&gt;
&lt;br /&gt;
::: ③ HW(하이워터마크) 경합**: 여러 인스턴스가 동시에 같은 테이블에 대량 INSERT → 세그먼트 확장 시 `enq: HW` 대기. ASSM이면 완화되지만, 극단적 동시 INSERT 워크로드면 파티셔닝으로 인스턴스별 물리적 분리 고려.&lt;br /&gt;
&lt;br /&gt;
::: ④ 애플리케이션 어피니티 부재**: 특정 데이터 범위를 특정 인스턴스로 유도하지 않고 무작위 라우팅하면, 같은 블록을 여러 인스턴스가 번갈아 요청해 GCS 트래픽(인터커넥트 부하)이 커집니다. Service 기반 워크로드 분산(각 서비스를 특정 인스턴스 선호로 라우팅)으로 완화 가능.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1825</id>
		<title>오라클 GCS 와 GES</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1825"/>
		<updated>2026-09-14T12:17:34Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== GCS(Global Cache Service)와 GES(Global Enqueue Service)==&lt;br /&gt;
* Oracle RAC의 핵심 메커니즘인 GCS(Global Cache Service)와 GES(Global Enqueue Service)는 여러 인스턴스가 하나의 데이터베이스를 동시에 접근할 때 **데이터 일관성**과 **자원 동기화**를 보장하는 두 축입니다.&lt;br /&gt;
&lt;br /&gt;
=== GCS (Global Cache Service) ===&lt;br /&gt;
::: — 캐시 퓨전(Cache Fusion)의 핵심&lt;br /&gt;
:여러 인스턴스의 버퍼캐시에 흩어져 있는 **동일 데이터 블록의 일관성**을 인스턴스 간 네트워크(인터커넥트)를 통해 관리합니다. &lt;br /&gt;
:::디스크를 거치지 않고 메모리-투-메모리로 블록을 주고받는 것이 핵심입니다.&lt;br /&gt;
&lt;br /&gt;
* 핵심 개념&lt;br /&gt;
:- Cache Fusion: 한 인스턴스가 수정한 블록을 다른 인스턴스가 요청하면, 디스크에 쓰지 않고 인터커넥트를 통해 블록을 직접 전송합니다.&lt;br /&gt;
&lt;br /&gt;
:- 자원 마스터링(Resource Mastering): 각 블록(정확히는 자원 단위)마다 어느 인스턴스가 &amp;quot;마스터&amp;quot;인지가 정해져 있고, 마스터 인스턴스가 해당 블록의 상태(누가 갖고 있는지, 어떤 모드인지)를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
:- 블록 상태(Role/Mode):&lt;br /&gt;
:: - **Role**: Local(단일 인스턴스만 사용 중) / Global(여러 인스턴스가 공유 중)&lt;br /&gt;
:: - **Mode**: NULL(공유 안 함), SHARED(읽기 공유), EXCLUSIVE(단독 수정)&lt;br /&gt;
&lt;br /&gt;
==== 동작 흐름 예시 ====&lt;br /&gt;
# Instance A가 블록을 수정하려고 함 → GCS에 EXCLUSIVE 권한 요청&lt;br /&gt;
# GCS 마스터가 &amp;quot;Instance B가 이미 이 블록을 갖고 있다&amp;quot;는 걸 확인&lt;br /&gt;
# B의 버퍼에서 A로 **직접 전송**(Cache Fusion) — 이때 상황에 따라 CR(Consistent Read) 이미지 또는 Current 블록 전송&lt;br /&gt;
# A가 수정 완료 후, 필요시 다시 다른 인스턴스 요청에 따라 전송 지속&lt;br /&gt;
&lt;br /&gt;
==== 관련 대기 이벤트 (성능 진단 시 자주 봄) ====&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `gc cr request` | 다른 인스턴스에 Consistent Read 블록 요청 후 대기 |&lt;br /&gt;
| `gc current request` | 다른 인스턴스에 Current 블록(수정용) 요청 후 대기 |&lt;br /&gt;
| `gc buffer busy acquire/release` | 로컬에서 블록을 이미 누가 가져오는 중이라 대기 |&lt;br /&gt;
| `gc cr/current block 2-way`, `3-way` | 2-way는 요청자↔소유자 직접, 3-way는 마스터를 거쳐 전달(인터커넥트 홉이 하나 더 생김 → 더 느림) |&lt;br /&gt;
&lt;br /&gt;
인터커넥트가 느리거나(네트워크 지연, private interconnect 대역폭 부족), 특정 블록에 여러 인스턴스가 동시에 몰리는 **Hot Block** 상황(자주 갱신되는 소수 로우, 시퀀스 없는 카운터 컬럼 등)이면 `gc` 대기가 급증합니다.&lt;br /&gt;
&lt;br /&gt;
=== GES (Global Enqueue Service) ===&lt;br /&gt;
— 자원 잠금 동기화&lt;br /&gt;
&lt;br /&gt;
GCS가 **데이터 블록** 자체를 다룬다면, GES는 그보다 더 넓은 범위의 **논리적 자원(enqueue)**에 대한 인스턴스 간 잠금 동기화를 담당합니다. 즉 &amp;quot;블록의 내용&amp;quot;이 아니라 &amp;quot;누가 무엇을 잠갔는지&amp;quot;를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
==== GES가 관리하는 대표적 자원 ====&lt;br /&gt;
- **TX (Transaction lock)**: 로우 레벨 락 — 여러 인스턴스에서 같은 로우를 수정하려 할 때 조율&lt;br /&gt;
- **TM (DML enqueue)**: 테이블 레벨 락 — DDL/DML 충돌 방지&lt;br /&gt;
- **각종 딕셔너리 캐시 락(dc_*)**: 데이터 딕셔너리 메타데이터 동기화&lt;br /&gt;
- **라이브러리 캐시 락(library cache lock, library cache pin)**: SQL/PL·SQL 커서, 오브젝트 정의 동기화&lt;br /&gt;
- **Sequence enqueue (SQ)**: 시퀀스 캐시 동기화 (NOORDER/캐시 크기에 따라 경합 발생 가능)&lt;br /&gt;
&lt;br /&gt;
**관련 대기 이벤트**&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `enq: TX - row lock contention` | 여러 세션(다른 인스턴스 포함)이 같은 로우를 잠그려 대기 |&lt;br /&gt;
| `enq: TM - contention` | 테이블 락 경합(FK 인덱스 없음 등이 원인인 경우 많음) |&lt;br /&gt;
| `enq: HW - contention` | High Water Mark 확장 경합 — 여러 인스턴스에서 동시 INSERT로 세그먼트 확장할 때 |&lt;br /&gt;
| `enq: SQ - contention` | 시퀀스 NEXTVAL 요청 경합 — 캐시 크기가 작거나 NOORDER 미설정 시 |&lt;br /&gt;
| `row cache lock` | 딕셔너리 캐시 자원 경합 |&lt;br /&gt;
&lt;br /&gt;
## GCS vs GES 핵심 차이&lt;br /&gt;
&lt;br /&gt;
| 구분 | GCS | GES |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 관리 대상 | 데이터 블록(버퍼캐시의 실제 내용) | 논리적 자원/락(TX, TM, dc_*, library cache 등) |&lt;br /&gt;
| 목적 | 블록 데이터의 인스턴스 간 일관성 유지 | 자원 접근 순서/배타성 보장 |&lt;br /&gt;
| 핵심 메커니즘 | Cache Fusion (메모리 간 직접 전송) | Enqueue 획득/대기/해제 프로토콜 |&lt;br /&gt;
| 진단 뷰 | `V$GC_ELEMENT`, `GV$CACHE_TRANSFER`, `GV$BH` | `V$GES_ENQUEUE`, `GV$LOCK`, `GV$GES_RESOURCE` |&lt;br /&gt;
| 프로세스 | LMS(Lock Manager Server) 프로세스가 실무 담당 | LMD(Lock Manager Daemon)가 enqueue 요청 처리, LMON이 전체 조율 |&lt;br /&gt;
&lt;br /&gt;
두 서비스 모두 **LMON, LMD, LMS** 백그라운드 프로세스가 협력해서 동작합니다:&lt;br /&gt;
- **LMON**: Global Enqueue Service Monitor — 클러스터 재구성(노드 추가/제거), 장애 감지 시 리마스터링 주도&lt;br /&gt;
- **LMD**: Global Enqueue Service Daemon — enqueue 요청/데드락 감지 처리&lt;br /&gt;
- **LMS**: Global Cache Service Process — 실제 블록 전송(Cache Fusion) 수행, 개수는 CPU 코어 수에 비례해 자동 설정&lt;br /&gt;
&lt;br /&gt;
## 실무에서 자주 마주치는 경합 패턴&lt;br /&gt;
&lt;br /&gt;
**① Hot Block 경합**: 순번 발급용 단일 로우를 여러 인스턴스에서 동시에 UPDATE하는 설계(카운터 테이블 등) → `gc buffer busy`/`enq: TX`가 폭증. 해결은 시퀀스 사용, 또는 파티셔닝으로 인스턴스별 분산.&lt;br /&gt;
&lt;br /&gt;
**② 시퀀스 경합**: `NOCACHE` 또는 `ORDER` 옵션 시퀀스를 RAC에서 사용하면 매번 GES를 거쳐 전역 순서를 보장해야 해서 경합 심함 → 순서 보장이 꼭 필요한 게 아니면 `CACHE` 크게 잡고 `NOORDER` 사용 권장.&lt;br /&gt;
&lt;br /&gt;
**③ HW(하이워터마크) 경합**: 여러 인스턴스가 동시에 같은 테이블에 대량 INSERT → 세그먼트 확장 시 `enq: HW` 대기. ASSM이면 완화되지만, 극단적 동시 INSERT 워크로드면 파티셔닝으로 인스턴스별 물리적 분리 고려.&lt;br /&gt;
&lt;br /&gt;
**④ 애플리케이션 어피니티 부재**: 특정 데이터 범위를 특정 인스턴스로 유도하지 않고 무작위 라우팅하면, 같은 블록을 여러 인스턴스가 번갈아 요청해 GCS 트래픽(인터커넥트 부하)이 커집니다. Service 기반 워크로드 분산(각 서비스를 특정 인스턴스 선호로 라우팅)으로 완화 가능.&lt;br /&gt;
&lt;br /&gt;
궁금하신 부분이 특정 대기 이벤트 분석(AWR RAC 리포트 해석)이나 실제 경합 진단 SQL 쪽이면 이어서 알려드릴 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1824</id>
		<title>오라클 GCS 와 GES</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_GCS_%EC%99%80_GES&amp;diff=1824"/>
		<updated>2026-09-14T12:09:51Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: == GCS(Global Cache Service)와 GES(Global Enqueue Service)== * Oracle RAC의 핵심 메커니즘인 GCS(Global Cache Service)와 GES(Global Enqueue Service)는 여러 인스턴스가 하나의 데이터베이스를 동시에 접근할 때 **데이터 일관성**과 **자원 동기화**를 보장하는 두 축입니다.  === GCS (Global Cache Service) === : — 캐시 퓨전(Cache Fusion)의 핵심 :여러 인스턴스의 버퍼캐시에 흩어져 있는 **동일 데이터 블...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== GCS(Global Cache Service)와 GES(Global Enqueue Service)==&lt;br /&gt;
* Oracle RAC의 핵심 메커니즘인 GCS(Global Cache Service)와 GES(Global Enqueue Service)는 여러 인스턴스가 하나의 데이터베이스를 동시에 접근할 때 **데이터 일관성**과 **자원 동기화**를 보장하는 두 축입니다.&lt;br /&gt;
&lt;br /&gt;
=== GCS (Global Cache Service) ===&lt;br /&gt;
: — 캐시 퓨전(Cache Fusion)의 핵심&lt;br /&gt;
:여러 인스턴스의 버퍼캐시에 흩어져 있는 **동일 데이터 블록의 일관성**을 인스턴스 간 네트워크(인터커넥트)를 통해 관리합니다. &lt;br /&gt;
:디스크를 거치지 않고 메모리-투-메모리로 블록을 주고받는 것이 핵심입니다.&lt;br /&gt;
&lt;br /&gt;
* 핵심 개념&lt;br /&gt;
:- Cache Fusion: 한 인스턴스가 수정한 블록을 다른 인스턴스가 요청하면, 디스크에 쓰지 않고 인터커넥트를 통해 블록을 직접 전송합니다.&lt;br /&gt;
&lt;br /&gt;
:- 자원 마스터링(Resource Mastering): 각 블록(정확히는 자원 단위)마다 어느 인스턴스가 &amp;quot;마스터&amp;quot;인지가 정해져 있고, 마스터 인스턴스가 해당 블록의 상태(누가 갖고 있는지, 어떤 모드인지)를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
:- 블록 상태(Role/Mode):&lt;br /&gt;
:: - **Role**: Local(단일 인스턴스만 사용 중) / Global(여러 인스턴스가 공유 중)&lt;br /&gt;
:: - **Mode**: NULL(공유 안 함), SHARED(읽기 공유), EXCLUSIVE(단독 수정)&lt;br /&gt;
&lt;br /&gt;
==== 동작 흐름 예시 ====&lt;br /&gt;
# Instance A가 블록을 수정하려고 함 → GCS에 EXCLUSIVE 권한 요청&lt;br /&gt;
# GCS 마스터가 &amp;quot;Instance B가 이미 이 블록을 갖고 있다&amp;quot;는 걸 확인&lt;br /&gt;
# B의 버퍼에서 A로 **직접 전송**(Cache Fusion) — 이때 상황에 따라 CR(Consistent Read) 이미지 또는 Current 블록 전송&lt;br /&gt;
# A가 수정 완료 후, 필요시 다시 다른 인스턴스 요청에 따라 전송 지속&lt;br /&gt;
&lt;br /&gt;
==== 관련 대기 이벤트 (성능 진단 시 자주 봄) ====&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `gc cr request` | 다른 인스턴스에 Consistent Read 블록 요청 후 대기 |&lt;br /&gt;
| `gc current request` | 다른 인스턴스에 Current 블록(수정용) 요청 후 대기 |&lt;br /&gt;
| `gc buffer busy acquire/release` | 로컬에서 블록을 이미 누가 가져오는 중이라 대기 |&lt;br /&gt;
| `gc cr/current block 2-way`, `3-way` | 2-way는 요청자↔소유자 직접, 3-way는 마스터를 거쳐 전달(인터커넥트 홉이 하나 더 생김 → 더 느림) |&lt;br /&gt;
&lt;br /&gt;
인터커넥트가 느리거나(네트워크 지연, private interconnect 대역폭 부족), 특정 블록에 여러 인스턴스가 동시에 몰리는 **Hot Block** 상황(자주 갱신되는 소수 로우, 시퀀스 없는 카운터 컬럼 등)이면 `gc` 대기가 급증합니다.&lt;br /&gt;
&lt;br /&gt;
=== GES (Global Enqueue Service) ===&lt;br /&gt;
— 자원 잠금 동기화&lt;br /&gt;
&lt;br /&gt;
GCS가 **데이터 블록** 자체를 다룬다면, GES는 그보다 더 넓은 범위의 **논리적 자원(enqueue)**에 대한 인스턴스 간 잠금 동기화를 담당합니다. 즉 &amp;quot;블록의 내용&amp;quot;이 아니라 &amp;quot;누가 무엇을 잠갔는지&amp;quot;를 관리합니다.&lt;br /&gt;
&lt;br /&gt;
==== GES가 관리하는 대표적 자원 ====&lt;br /&gt;
- **TX (Transaction lock)**: 로우 레벨 락 — 여러 인스턴스에서 같은 로우를 수정하려 할 때 조율&lt;br /&gt;
- **TM (DML enqueue)**: 테이블 레벨 락 — DDL/DML 충돌 방지&lt;br /&gt;
- **각종 딕셔너리 캐시 락(dc_*)**: 데이터 딕셔너리 메타데이터 동기화&lt;br /&gt;
- **라이브러리 캐시 락(library cache lock, library cache pin)**: SQL/PL·SQL 커서, 오브젝트 정의 동기화&lt;br /&gt;
- **Sequence enqueue (SQ)**: 시퀀스 캐시 동기화 (NOORDER/캐시 크기에 따라 경합 발생 가능)&lt;br /&gt;
&lt;br /&gt;
**관련 대기 이벤트**&lt;br /&gt;
| 이벤트 | 의미 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| `enq: TX - row lock contention` | 여러 세션(다른 인스턴스 포함)이 같은 로우를 잠그려 대기 |&lt;br /&gt;
| `enq: TM - contention` | 테이블 락 경합(FK 인덱스 없음 등이 원인인 경우 많음) |&lt;br /&gt;
| `enq: HW - contention` | High Water Mark 확장 경합 — 여러 인스턴스에서 동시 INSERT로 세그먼트 확장할 때 |&lt;br /&gt;
| `enq: SQ - contention` | 시퀀스 NEXTVAL 요청 경합 — 캐시 크기가 작거나 NOORDER 미설정 시 |&lt;br /&gt;
| `row cache lock` | 딕셔너리 캐시 자원 경합 |&lt;br /&gt;
&lt;br /&gt;
## GCS vs GES 핵심 차이&lt;br /&gt;
&lt;br /&gt;
| 구분 | GCS | GES |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 관리 대상 | 데이터 블록(버퍼캐시의 실제 내용) | 논리적 자원/락(TX, TM, dc_*, library cache 등) |&lt;br /&gt;
| 목적 | 블록 데이터의 인스턴스 간 일관성 유지 | 자원 접근 순서/배타성 보장 |&lt;br /&gt;
| 핵심 메커니즘 | Cache Fusion (메모리 간 직접 전송) | Enqueue 획득/대기/해제 프로토콜 |&lt;br /&gt;
| 진단 뷰 | `V$GC_ELEMENT`, `GV$CACHE_TRANSFER`, `GV$BH` | `V$GES_ENQUEUE`, `GV$LOCK`, `GV$GES_RESOURCE` |&lt;br /&gt;
| 프로세스 | LMS(Lock Manager Server) 프로세스가 실무 담당 | LMD(Lock Manager Daemon)가 enqueue 요청 처리, LMON이 전체 조율 |&lt;br /&gt;
&lt;br /&gt;
두 서비스 모두 **LMON, LMD, LMS** 백그라운드 프로세스가 협력해서 동작합니다:&lt;br /&gt;
- **LMON**: Global Enqueue Service Monitor — 클러스터 재구성(노드 추가/제거), 장애 감지 시 리마스터링 주도&lt;br /&gt;
- **LMD**: Global Enqueue Service Daemon — enqueue 요청/데드락 감지 처리&lt;br /&gt;
- **LMS**: Global Cache Service Process — 실제 블록 전송(Cache Fusion) 수행, 개수는 CPU 코어 수에 비례해 자동 설정&lt;br /&gt;
&lt;br /&gt;
## 실무에서 자주 마주치는 경합 패턴&lt;br /&gt;
&lt;br /&gt;
**① Hot Block 경합**: 순번 발급용 단일 로우를 여러 인스턴스에서 동시에 UPDATE하는 설계(카운터 테이블 등) → `gc buffer busy`/`enq: TX`가 폭증. 해결은 시퀀스 사용, 또는 파티셔닝으로 인스턴스별 분산.&lt;br /&gt;
&lt;br /&gt;
**② 시퀀스 경합**: `NOCACHE` 또는 `ORDER` 옵션 시퀀스를 RAC에서 사용하면 매번 GES를 거쳐 전역 순서를 보장해야 해서 경합 심함 → 순서 보장이 꼭 필요한 게 아니면 `CACHE` 크게 잡고 `NOORDER` 사용 권장.&lt;br /&gt;
&lt;br /&gt;
**③ HW(하이워터마크) 경합**: 여러 인스턴스가 동시에 같은 테이블에 대량 INSERT → 세그먼트 확장 시 `enq: HW` 대기. ASSM이면 완화되지만, 극단적 동시 INSERT 워크로드면 파티셔닝으로 인스턴스별 물리적 분리 고려.&lt;br /&gt;
&lt;br /&gt;
**④ 애플리케이션 어피니티 부재**: 특정 데이터 범위를 특정 인스턴스로 유도하지 않고 무작위 라우팅하면, 같은 블록을 여러 인스턴스가 번갈아 요청해 GCS 트래픽(인터커넥트 부하)이 커집니다. Service 기반 워크로드 분산(각 서비스를 특정 인스턴스 선호로 라우팅)으로 완화 가능.&lt;br /&gt;
&lt;br /&gt;
궁금하신 부분이 특정 대기 이벤트 분석(AWR RAC 리포트 해석)이나 실제 경합 진단 SQL 쪽이면 이어서 알려드릴 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1823</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1823"/>
		<updated>2026-09-14T11:38:25Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 일반 블록 vs LOB 블록의 근본적 차이 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1822</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1822"/>
		<updated>2026-09-14T11:18:52Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== ASSM과 LOB의 상호작용 (RAC 필수 지식)===&lt;br /&gt;
==== 반드시 ASSM 사용해야 하는 이유 ====&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*MSSM(Manual) vs ASSM(Auto) 차이&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
==== RETENTION vs PCTVERSION - RAC에서의 실질적 차이 ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 이유 : PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== SecureFile의 RAC 최적화 메커니즘 (핵심) ===&lt;br /&gt;
==== Write Gathering (쓰기 병합) ====&lt;br /&gt;
* SecureFile은 내부적으로 여러 개의 작은 쓰기를 병합하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1821</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1821"/>
		<updated>2026-09-14T11:13:52Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
## 3. ASSM과 LOB의 상호작용 (RAC 필수 지식)&lt;br /&gt;
&lt;br /&gt;
### 3.1 반드시 ASSM 사용해야 하는 이유&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**MSSM(Manual) vs ASSM(Auto) 차이**:&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
### 3.2 RETENTION vs PCTVERSION - RAC에서의 실질적 차이&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**이유**: PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. SecureFile의 RAC 최적화 메커니즘 (핵심)&lt;br /&gt;
&lt;br /&gt;
### 4.1 Write Gathering (쓰기 병합)&lt;br /&gt;
&lt;br /&gt;
SecureFile은 내부적으로 **여러 개의 작은 쓰기를 병합**하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
```&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1820</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1820"/>
		<updated>2026-09-14T11:06:11Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:* 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
#:* 시나리오: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*핵심 대기 이벤트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
#: *원리*: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 인스턴스 간 직렬화가 필요합니다.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
#:*시나리오 재현&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
## 3. ASSM과 LOB의 상호작용 (RAC 필수 지식)&lt;br /&gt;
&lt;br /&gt;
### 3.1 반드시 ASSM 사용해야 하는 이유&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**MSSM(Manual) vs ASSM(Auto) 차이**:&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
### 3.2 RETENTION vs PCTVERSION - RAC에서의 실질적 차이&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**이유**: PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. SecureFile의 RAC 최적화 메커니즘 (핵심)&lt;br /&gt;
&lt;br /&gt;
### 4.1 Write Gathering (쓰기 병합)&lt;br /&gt;
&lt;br /&gt;
SecureFile은 내부적으로 **여러 개의 작은 쓰기를 병합**하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
```&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1819</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1819"/>
		<updated>2026-09-14T11:00:50Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
# 경합 지점 #1: LOB Index Contention&lt;br /&gt;
#:*메커니즘 : LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대기 이벤트 시그니처&lt;br /&gt;
#:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
# 실전 확인 쿼리&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
### 2.2 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
&lt;br /&gt;
**시나리오**: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**핵심 대기 이벤트**:&lt;br /&gt;
```sql&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2.3 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
&lt;br /&gt;
**원리**: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 **인스턴스 간 직렬화**가 필요합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**시나리오 재현**:&lt;br /&gt;
```&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. ASSM과 LOB의 상호작용 (RAC 필수 지식)&lt;br /&gt;
&lt;br /&gt;
### 3.1 반드시 ASSM 사용해야 하는 이유&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**MSSM(Manual) vs ASSM(Auto) 차이**:&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
### 3.2 RETENTION vs PCTVERSION - RAC에서의 실질적 차이&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**이유**: PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. SecureFile의 RAC 최적화 메커니즘 (핵심)&lt;br /&gt;
&lt;br /&gt;
### 4.1 Write Gathering (쓰기 병합)&lt;br /&gt;
&lt;br /&gt;
SecureFile은 내부적으로 **여러 개의 작은 쓰기를 병합**하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
```&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1818</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1818"/>
		<updated>2026-09-14T10:54:46Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 경합 지점별 상세 분석 ===&lt;br /&gt;
&lt;br /&gt;
### 2.1 경합 지점 #1: LOB Index Contention&lt;br /&gt;
&lt;br /&gt;
**메커니즘**: LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**대기 이벤트 시그니처**:&lt;br /&gt;
```&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실전 확인 쿼리**:&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2.2 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
&lt;br /&gt;
**시나리오**: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**핵심 대기 이벤트**:&lt;br /&gt;
```sql&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2.3 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
&lt;br /&gt;
**원리**: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 **인스턴스 간 직렬화**가 필요합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**시나리오 재현**:&lt;br /&gt;
```&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. ASSM과 LOB의 상호작용 (RAC 필수 지식)&lt;br /&gt;
&lt;br /&gt;
### 3.1 반드시 ASSM 사용해야 하는 이유&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**MSSM(Manual) vs ASSM(Auto) 차이**:&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
### 3.2 RETENTION vs PCTVERSION - RAC에서의 실질적 차이&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**이유**: PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. SecureFile의 RAC 최적화 메커니즘 (핵심)&lt;br /&gt;
&lt;br /&gt;
### 4.1 Write Gathering (쓰기 병합)&lt;br /&gt;
&lt;br /&gt;
SecureFile은 내부적으로 **여러 개의 작은 쓰기를 병합**하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
```&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1817</id>
		<title>RAC환경 lob 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=RAC%ED%99%98%EA%B2%BD_lob_%ED%8A%9C%EB%8B%9D&amp;diff=1817"/>
		<updated>2026-09-14T10:48:26Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: == RAC 환경 LOB 튜닝 == # RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석 # 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?  === 일반 블록 vs LOB 블록의 근본적 차이 ===  * 일반 데이터 블록 (Cache Fusion 대상) &amp;lt;source lang=sql&amp;gt;     → 상대적으로 작고 균일한 크기     → 블록 단위 공유가 예측 가능 &amp;lt;/source&amp;gt;  * LOB 청크 (CHUNK) &amp;lt;source lang=sql&amp;gt;     → 크기가 크고(보통 8K~32K), 여러...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== RAC 환경 LOB 튜닝 ==&lt;br /&gt;
# RAC 환경에서의 LOB 동시성 이슈 - 전문가 심화 분석&lt;br /&gt;
# 문제의 본질: 왜 LOB이 RAC에서 특별히 까다로운가?&lt;br /&gt;
&lt;br /&gt;
=== 일반 블록 vs LOB 블록의 근본적 차이 ===&lt;br /&gt;
&lt;br /&gt;
* 일반 데이터 블록 (Cache Fusion 대상)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 상대적으로 작고 균일한 크기&lt;br /&gt;
    → 블록 단위 공유가 예측 가능&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* LOB 청크 (CHUNK)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
    → 크기가 크고(보통 8K~32K), 여러 블록으로 구성&lt;br /&gt;
    → 하나의 LOB 조작이 다수의 블록을 한번에 건드림&lt;br /&gt;
    → Cache Fusion 전송 비용이 일반 블록보다 훨씬 큼&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 문제: RAC의 Cache Fusion은 &amp;quot;블록 단위&amp;quot; 공유를 전제로 설계되었는데, LOB은 대용량 데이터 특성상 이 모델과 근본적으로 마찰이 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB의 3단 구조가 만드는 3중 경합 지점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Instance 1                          Instance 2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Locator] ──────GES 관리──────► [LOB Locator]&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Index] ◄──── GCS/GES 경합 ────► [LOB Index]   ← 경합 지점 #1&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[LOB Segment] ◄─── GCS 경합 ───────► [LOB Segment] ← 경합 지점 #2&lt;br /&gt;
    │                                    │&lt;br /&gt;
    ▼                                    ▼&lt;br /&gt;
[HWM/Extent] ◄──── HW Enqueue ─────► [HWM/Extent]  ← 경합 지점 #3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. 경합 지점별 상세 분석&lt;br /&gt;
&lt;br /&gt;
### 2.1 경합 지점 #1: LOB Index Contention&lt;br /&gt;
&lt;br /&gt;
**메커니즘**: LOB Index는 B-Tree 구조이므로, 여러 인스턴스에서 동시에 LOB INSERT가 발생하면 인덱스 리프 블록에 대한 경합 발생.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 이 대기 이벤트가 자주 보이면 LOB Index 경합 의심&lt;br /&gt;
SELECT event, count(*)&lt;br /&gt;
FROM v$session&lt;br /&gt;
WHERE event LIKE &#039;%TX%&#039; OR event LIKE &#039;%index contention%&#039;&lt;br /&gt;
GROUP BY event;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**대기 이벤트 시그니처**:&lt;br /&gt;
```&lt;br /&gt;
enq: TX - index contention          -- LOB Index 리프 블록 분할 경합&lt;br /&gt;
gc buffer busy acquire               -- LOB Index 블록의 노드간 전송 대기&lt;br /&gt;
gc cr block busy                     -- Consistent Read 블록 요청 지연&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실전 확인 쿼리**:&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    a.inst_id, a.sid, a.event, a.p1, a.p2, a.p3,&lt;br /&gt;
    o.object_name, o.object_type&lt;br /&gt;
FROM gv$session_wait a, dba_objects o&lt;br /&gt;
WHERE a.event LIKE &#039;%gc%&#039;&lt;br /&gt;
  AND a.p1 = o.object_id  -- 근사치, 실제로는 block 매핑 필요&lt;br /&gt;
  AND o.object_type = &#039;LOB&#039;&lt;br /&gt;
ORDER BY a.inst_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2.2 경합 지점 #2: LOB Segment Cache Fusion 경합&lt;br /&gt;
&lt;br /&gt;
**시나리오**: Instance 1과 Instance 2가 동일 LOB 세그먼트의 인접한 CHUNK에 동시 쓰기 시도.&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
Instance 1: INSERT INTO t (id, doc) VALUES (1, &#039;대용량문서A&#039;)&lt;br /&gt;
                → CHUNK #501 할당 요청&lt;br /&gt;
&lt;br /&gt;
Instance 2: INSERT INTO t (id, doc) VALUES (2, &#039;대용량문서B&#039;)  &lt;br /&gt;
                → CHUNK #502 할당 요청 (인접 블록)&lt;br /&gt;
                &lt;br /&gt;
    → 같은 세그먼트 헤더/비트맵 블록 경합 발생&lt;br /&gt;
    → &amp;quot;gc buffer busy&amp;quot; 또는 &amp;quot;gc current block busy&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**핵심 대기 이벤트**:&lt;br /&gt;
```sql&lt;br /&gt;
-- AWR에서 확인&lt;br /&gt;
SELECT event, total_waits, time_waited_micro/1000000 AS sec&lt;br /&gt;
FROM dba_hist_system_event&lt;br /&gt;
WHERE event IN (&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;, &lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;gc current grant busy&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY time_waited_micro DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2.3 경합 지점 #3: HW (High Water Mark) Enqueue - 가장 흔한 실전 문제&lt;br /&gt;
&lt;br /&gt;
**원리**: LOB Segment가 확장(extent 추가)될 때 HWM을 이동시켜야 하는데, 이 작업은 **인스턴스 간 직렬화**가 필요합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 실제 프로덕션에서 가장 흔하게 목격되는 패턴&lt;br /&gt;
SELECT inst_id, event, count(*), avg(wait_time)&lt;br /&gt;
FROM gv$session_wait_history&lt;br /&gt;
WHERE event = &#039;enq: HW - contention&#039;&lt;br /&gt;
GROUP BY inst_id, event;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**시나리오 재현**:&lt;br /&gt;
```&lt;br /&gt;
[Instance 1]                    [Instance 2]&lt;br /&gt;
LOB INSERT 대량 발생                LOB INSERT 대량 발생&lt;br /&gt;
    │                                   │&lt;br /&gt;
    ▼                                   ▼&lt;br /&gt;
Extent 소진 → HWM 이동 필요      Extent 소진 → HWM 이동 필요&lt;br /&gt;
    │                                   │&lt;br /&gt;
    └──────► HW Enqueue 대기 직렬화 ◄───┘&lt;br /&gt;
    &lt;br /&gt;
    결과: 두 인스턴스 모두 &amp;quot;enq: HW - contention&amp;quot; 대기&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. ASSM과 LOB의 상호작용 (RAC 필수 지식)&lt;br /&gt;
&lt;br /&gt;
### 3.1 반드시 ASSM 사용해야 하는 이유&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Tablespace 생성 시 반드시 확인&lt;br /&gt;
SELECT tablespace_name, segment_space_management&lt;br /&gt;
FROM dba_tablespaces&lt;br /&gt;
WHERE tablespace_name = &#039;YOUR_LOB_TS&#039;;&lt;br /&gt;
-- segment_space_management = &#039;AUTO&#039; 여야 함&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**MSSM(Manual) vs ASSM(Auto) 차이**:&lt;br /&gt;
&lt;br /&gt;
| 구분 | MSSM (FREELIST) | ASSM (Bitmap) |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| RAC 확장성 | FREELIST GROUPS 수동 구성 필요 | 자동으로 인스턴스별 분산 |&lt;br /&gt;
| HW 경합 | 매우 심함 | 상대적으로 완화 |&lt;br /&gt;
| 권장 여부 | ❌ RAC에서 지양 | ✅ 필수 권장 |&lt;br /&gt;
&lt;br /&gt;
### 3.2 RETENTION vs PCTVERSION - RAC에서의 실질적 차이&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경에서는 RETENTION 방식이 유리&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts   -- ASSM 필수&lt;br /&gt;
    RETENTION            -- PCTVERSION 대신 권장&lt;br /&gt;
    ...&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**이유**: PCTVERSION은 &amp;quot;공간 비율&amp;quot; 기반이라 다중 인스턴스의 동시 버전 생성 패턴을 예측하기 어려움. RETENTION(시간 기반)이 UNDO_RETENTION과 일관되게 동작하여 다중 인스턴스 환경에서 더 예측 가능.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. SecureFile의 RAC 최적화 메커니즘 (핵심)&lt;br /&gt;
&lt;br /&gt;
### 4.1 Write Gathering (쓰기 병합)&lt;br /&gt;
&lt;br /&gt;
SecureFile은 내부적으로 **여러 개의 작은 쓰기를 병합**하여 Cache Fusion 전송 횟수를 줄입니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- SecureFile 내부 최적화 확인 (간접적)&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$sysstat&lt;br /&gt;
WHERE name LIKE &#039;%securefile%&#039; OR name LIKE &#039;%lob%&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
주요 통계:&lt;br /&gt;
```&lt;br /&gt;
securefile direct read bytes&lt;br /&gt;
securefile direct write bytes&lt;br /&gt;
securefile number of non-transformed reads&lt;br /&gt;
securefile bytes non-transformed via cache&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 4.2 Space Reservation (공간 예약) - RAC HW 경합 완화 핵심 기법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts&lt;br /&gt;
    CHUNK 8192&lt;br /&gt;
    RETENTION&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 10M&lt;br /&gt;
        NEXT 10M          -- 더 큰 단위로 미리 확장하여 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**전략**: Extent 크기를 크게 잡아서(NEXT 값 상향) HW 이동 **빈도 자체**를 줄이는 것이 RAC에서 매우 효과적.&lt;br /&gt;
&lt;br /&gt;
### 4.3 SecureFile 필수 확인 - 인스턴스별 Segment 분산&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- Oracle 11g R2 이후 SecureFile은 내부적으로 &lt;br /&gt;
-- 인스턴스 어피니티(affinity)를 고려한 익스텐트 할당 로직 보유&lt;br /&gt;
SELECT &lt;br /&gt;
    inst_id, &lt;br /&gt;
    segment_name,&lt;br /&gt;
    extent_id,&lt;br /&gt;
    bytes&lt;br /&gt;
FROM gv$... -- 실제로는 x$ 뷰 레벨 분석 필요 (kcbsw 등)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. 실전 시나리오별 분석&lt;br /&gt;
&lt;br /&gt;
### 5.1 시나리오 A: 다중 노드 로그 적재 시스템&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 5개 RAC 노드에서 동시에 CLOB 로그 INSERT&lt;br /&gt;
- 초당 수천 건 발생&lt;br /&gt;
- &amp;quot;enq: HW - contention&amp;quot; 대기가 전체 대기의 40% 차지&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- 1. 익스텐트 크기 대폭 상향&lt;br /&gt;
ALTER TABLE log_table MODIFY LOB (log_data) (&lt;br /&gt;
    STORAGE (NEXT 100M)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 2. 인스턴스별 파티셔닝 고려 (근본적 해결)&lt;br /&gt;
CREATE TABLE log_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    inst_id NUMBER,&lt;br /&gt;
    log_data CLOB&lt;br /&gt;
) PARTITION BY LIST (inst_id) (&lt;br /&gt;
    PARTITION p1 VALUES (1),&lt;br /&gt;
    PARTITION p2 VALUES (2),&lt;br /&gt;
    PARTITION p3 VALUES (3)&lt;br /&gt;
    -- 각 인스턴스가 자신의 파티션에만 쓰기 → HW 경합 원천 차단&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 5.2 시나리오 B: LOB 인덱스 리프 블록 스플릿 경합&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
문제 상황:&lt;br /&gt;
- 순차적이지 않은 LOB ID로 동시 INSERT (예: GUID 기반)&lt;br /&gt;
- 여러 노드가 인덱스의 서로 다른 위치에 리프 스플릿 유발&lt;br /&gt;
- &amp;quot;gc buffer busy acquire&amp;quot; 이벤트 급증&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**해결 접근법**:&lt;br /&gt;
```sql&lt;br /&gt;
-- Reverse Key Index와 유사한 개념이 LOB Index에는 직접 적용 불가&lt;br /&gt;
-- 대신 애플리케이션 레벨 해시 분산 고려&lt;br /&gt;
&lt;br /&gt;
-- 또는 LOB Index를 위한 별도 튜닝 (드문 케이스)&lt;br /&gt;
-- Interested Transaction List(ITL) 관련 파라미터 검토&lt;br /&gt;
ALTER TABLE lob_test MODIFY LOB (doc) (&lt;br /&gt;
    STORE AS SECUREFILE (...)&lt;br /&gt;
) ; -- INITRANS 상향 검토 필요할 수 있음&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. CACHE 옵션과 RAC Global Cache의 실질적 관계&lt;br /&gt;
&lt;br /&gt;
### 6.1 중요한 오해 정정&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&amp;quot;CACHE로 설정하면 RAC에서 자동으로 전 노드에 캐싱된다&amp;quot;&lt;br /&gt;
→ 반은 맞고 반은 틀림&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**실제 동작**:&lt;br /&gt;
```&lt;br /&gt;
CACHE 옵션 = Buffer Cache 사용 여부 결정 (로컬 인스턴스 관점)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Buffer Cache에 있는 LOB 블록은 여전히 Cache Fusion 프로토콜 따름&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
즉, CACHE 설정 시 오히려 Cache Fusion 트래픽이 증가할 수 있음&lt;br /&gt;
(NOCACHE는 Direct Path I/O라서 애초에 Global Cache 경합이 적음)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 6.2 RAC에서의 실전 권장사항&lt;br /&gt;
&lt;br /&gt;
| 워크로드 패턴 | 권장 옵션 | 이유 |&lt;br /&gt;
|---|---|---|&lt;br /&gt;
| 대용량, 1회성, 노드 분산 접근 | **NOCACHE** | Direct I/O로 Cache Fusion 우회 → 경합 최소화 |&lt;br /&gt;
| 소용량, 특정 노드 반복 접근 | CACHE | 로컬 캐싱 이득 &amp;gt; Cache Fusion 비용 |&lt;br /&gt;
| 다중 노드 랜덤 접근, 중간 크기 | CACHE READS | 쓰기는 우회, 읽기만 캐싱 |&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- RAC 환경 대용량 첨부파일 시스템 권장 설정&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    NOCACHE           -- Global Cache 경합 원천 차단&lt;br /&gt;
    NOLOGGING         -- 가능한 경우 (Standby 고려 필요)&lt;br /&gt;
    CHUNK 32768        -- 큰 청크로 I/O 효율 극대화&lt;br /&gt;
)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Parallel DML + LOB + RAC 삼중 복잡도&lt;br /&gt;
&lt;br /&gt;
### 7.1 병렬 INSERT 시 발생하는 문제&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
ALTER SESSION ENABLE PARALLEL DML;&lt;br /&gt;
&lt;br /&gt;
INSERT /*+ PARALLEL(4) */ INTO lob_test&lt;br /&gt;
SELECT id, large_doc FROM source_table;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**내부 동작**:&lt;br /&gt;
```&lt;br /&gt;
Parallel Slave 1 (Node A) ──┐&lt;br /&gt;
Parallel Slave 2 (Node A) ──┼──► 동일 LOB Segment에 동시 쓰기&lt;br /&gt;
Parallel Slave 3 (Node B) ──┤     → HW enqueue 경합 극대화&lt;br /&gt;
Parallel Slave 4 (Node B) ──┘&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**완화 전략**:&lt;br /&gt;
```sql&lt;br /&gt;
-- PDML + LOB 사용 시 필수 고려사항&lt;br /&gt;
-- 1) 충분히 큰 익스텐트 사이즈 사전 확보&lt;br /&gt;
-- 2) 가능하면 병렬도를 노드 수의 배수로 제한하지 않고 &lt;br /&gt;
--    단일 노드 집중 실행 고려 (역설적이지만 효과적일 때 있음)&lt;br /&gt;
ALTER SESSION SET INSTANCE_GROUPS = &#039;single_node_group&#039;;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. 실전 모니터링 스크립트&lt;br /&gt;
&lt;br /&gt;
### 8.1 종합 LOB RAC 경합 진단 쿼리&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- LOB 관련 대기 이벤트 종합 (AWR 기반)&lt;br /&gt;
SELECT &lt;br /&gt;
    dhse.instance_number,&lt;br /&gt;
    dhse.event_name,&lt;br /&gt;
    dhse.total_waits,&lt;br /&gt;
    ROUND(dhse.time_waited_micro/1000000, 2) AS wait_sec&lt;br /&gt;
FROM dba_hist_system_event dhse&lt;br /&gt;
WHERE dhse.event_name IN (&lt;br /&gt;
    &#039;enq: HW - contention&#039;,&lt;br /&gt;
    &#039;enq: TX - index contention&#039;,&lt;br /&gt;
    &#039;gc buffer busy acquire&#039;,&lt;br /&gt;
    &#039;gc buffer busy release&#039;,&lt;br /&gt;
    &#039;gc current block busy&#039;,&lt;br /&gt;
    &#039;gc cr block busy&#039;,&lt;br /&gt;
    &#039;direct path write&#039;,&lt;br /&gt;
    &#039;direct path read&#039;&lt;br /&gt;
)&lt;br /&gt;
AND dhse.snap_id = (SELECT MAX(snap_id) FROM dba_hist_snapshot)&lt;br /&gt;
ORDER BY wait_sec DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.2 실시간 세션 레벨 진단&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT &lt;br /&gt;
    s.inst_id, s.sid, s.serial#, s.event,&lt;br /&gt;
    s.seconds_in_wait,&lt;br /&gt;
    s.program,&lt;br /&gt;
    sql.sql_text&lt;br /&gt;
FROM gv$session s, gv$sql sql&lt;br /&gt;
WHERE s.sql_id = sql.sql_id(+)&lt;br /&gt;
  AND (s.event LIKE &#039;%gc%&#039; OR s.event LIKE &#039;%HW%&#039;)&lt;br /&gt;
  AND s.wait_class != &#039;Idle&#039;&lt;br /&gt;
ORDER BY s.seconds_in_wait DESC;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 8.3 LOB 세그먼트별 익스텐트 분산 확인&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 익스텐트가 특정 노드/인스턴스에 편중되어 있는지 확인&lt;br /&gt;
SELECT &lt;br /&gt;
    owner, segment_name, &lt;br /&gt;
    extent_id, bytes, blocks,&lt;br /&gt;
    relative_fno&lt;br /&gt;
FROM dba_extents&lt;br /&gt;
WHERE segment_name = (&lt;br /&gt;
    SELECT segment_name FROM dba_lobs &lt;br /&gt;
    WHERE table_name = &#039;YOUR_TABLE&#039;&lt;br /&gt;
)&lt;br /&gt;
ORDER BY extent_id;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. 종합 Best Practice 체크리스트 (RAC + LOB)&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 최종 권장 템플릿&lt;br /&gt;
CREATE TABLE rac_optimized_lob_table (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    partition_key NUMBER,  -- 인스턴스/노드 분산용 컬럼 고려&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) &lt;br /&gt;
PARTITION BY HASH (partition_key) PARTITIONS 8  -- 경합 원천 분산&lt;br /&gt;
LOB (doc) STORE AS SECUREFILE (&lt;br /&gt;
    TABLESPACE lob_ts        -- ASSM 필수 확인&lt;br /&gt;
    ENABLE STORAGE IN ROW&lt;br /&gt;
    CHUNK 16384                -- 워크로드에 맞게 조정&lt;br /&gt;
    RETENTION                  -- PCTVERSION 대신&lt;br /&gt;
    NOCACHE                    -- RAC 경합 최소화 (워크로드별 조정)&lt;br /&gt;
    COMPRESS MEDIUM            -- I/O 자체를 줄여 경합 시간 단축&lt;br /&gt;
    STORAGE (&lt;br /&gt;
        INITIAL 50M&lt;br /&gt;
        NEXT 50M              -- 큰 익스텐트로 HW 이동 빈도 감소&lt;br /&gt;
        MAXEXTENTS UNLIMITED&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 체크리스트&lt;br /&gt;
| 항목 | 확인 사항 |&lt;br /&gt;
|---|---|&lt;br /&gt;
| ☑ Tablespace | ASSM (AUTO Segment Space Management) 여부 |&lt;br /&gt;
| ☑ LOB Type | SecureFile 사용 여부 (BasicFile 지양) |&lt;br /&gt;
| ☑ Extent 전략 | 큰 NEXT 값으로 HW 이동 빈도 최소화 |&lt;br /&gt;
| ☑ 파티셔닝 | 가능하면 노드/워크로드 특성 따라 분산 |&lt;br /&gt;
| ☑ CACHE 옵션 | 워크로드 패턴에 맞게 선택 (기본 NOCACHE 권장) |&lt;br /&gt;
| ☑ RETENTION | PCTVERSION 대신 RETENTION 사용 검토 |&lt;br /&gt;
| ☑ 모니터링 | HW/gc buffer busy 이벤트 정기 추적 |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 핵심 요약&lt;br /&gt;
&lt;br /&gt;
1. **HW Enqueue**가 RAC + LOB 환경에서 가장 흔하고 치명적인 경합 → **큰 익스텐트 크기**로 완화&lt;br /&gt;
2. **ASSM은 선택이 아닌 필수** - MSSM은 RAC에서 사실상 사용 불가 수준&lt;br /&gt;
3. **SecureFile의 Write Gathering**이 Cache Fusion 트래픽을 내부적으로 최적화&lt;br /&gt;
4. **NOCACHE가 RAC에서는 오히려 유리한 경우가 많음** (Direct I/O로 Global Cache 우회)&lt;br /&gt;
5. **파티셔닝을 통한 물리적 분산**이 근본적 해결책 (경합 자체를 원천 차단)&lt;br /&gt;
6. **PCTVERSION보다 RETENTION**이 다중 인스턴스 환경에서 예측 가능성이 높음&lt;br /&gt;
&lt;br /&gt;
더 깊이 다뤄볼 만한 주제로 **Exadata Smart Scan과 LOB의 상호작용**, **GoldenGate/Data Guard 환경에서 SecureFile LOB 복제 시 이슈**, 또는 **AWR/ASH 리포트를 활용한 실전 LOB 경합 튜닝 케이스 스터디** 등이 있는데, 관심 있으신 영역 있으신가요?&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1771</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1771"/>
		<updated>2026-09-09T01:37:14Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
:::*파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1770</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1770"/>
		<updated>2026-09-09T01:36:51Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
:::*파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1769</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1769"/>
		<updated>2026-09-09T01:07:08Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 실제 확보된 UNDO 보존 이력 확인 (핵심) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
:::*파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1768</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1768"/>
		<updated>2026-09-09T01:06:57Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 실제 확보된 UNDO 보존 이력 확인 (핵심) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
:::**파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1767</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1767"/>
		<updated>2026-09-09T01:06:30Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 실제 확보된 UNDO 보존 이력 확인 (핵심) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1766</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1766"/>
		<updated>2026-09-09T01:05:59Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Guarantee 여부 확인 (매우 중요) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1765</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1765"/>
		<updated>2026-09-09T01:04:50Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Guarantee 여부 확인 (매우 중요) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
::::- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
::::- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1764</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1764"/>
		<updated>2026-09-08T02:21:28Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 복구 가능한 시간을 확인 하는법 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Guarantee 여부 확인 (매우 중요) ===&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT tablespace_name, retention, contents, status&lt;br /&gt;
  FROM dba_tablespaces&lt;br /&gt;
 WHERE tablespace_name = (&lt;br /&gt;
    SELECT UPPER(value) FROM v$parameter WHERE name = &#039;undo_tablespace&#039;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:::*RETENTION 컬럼 값:&lt;br /&gt;
- GUARANTEE    → UNDO_RETENTION 시간을 반드시 보장 (DML 실패 위험 감수)&lt;br /&gt;
- NOGUARANTEE  → 공간 부족 시 오래된 UNDO 우선 재사용 (기본값)&lt;br /&gt;
&lt;br /&gt;
-- GUARANTEE로 변경 (운영 영향 주의: 공간부족 시 트랜잭션 실패 가능)&lt;br /&gt;
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;&lt;br /&gt;
&lt;br /&gt;
=== 실제 확보된 UNDO 보존 이력 확인 (핵심) ===&lt;br /&gt;
파라미터 설정값이 아니라 실제로 시스템이 유지해온 이력을 확인하는 것이 훨씬 정확합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- ============================================&lt;br /&gt;
-- V$UNDOSTAT: 10분 단위로 실제 통계 기록 (최대 4일치 보관)&lt;br /&gt;
-- ============================================&lt;br /&gt;
SELECT &lt;br /&gt;
    TO_CHAR(begin_time, &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS begin_time,&lt;br /&gt;
    TO_CHAR(end_time,   &#039;YYYY-MM-DD HH24:MI:SS&#039;) AS end_time,&lt;br /&gt;
    undoblks,&lt;br /&gt;
    txncount,&lt;br /&gt;
    maxquerylen,           -- 이 구간 중 실행된 최장 쿼리 길이(초)&lt;br /&gt;
    maxqueryid,&lt;br /&gt;
    tuned_undoretention    -- 시스템이 실제로 튜닝한 보존시간(초)&lt;br /&gt;
FROM v$undostat&lt;br /&gt;
ORDER BY end_time DESC;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실질적으로 가장 중요한 지표: 전체 데이터의 최고(最古) 시점 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- v$undostat에 기록된 가장 오래된 시점 = 통계상 조회 가능한 하한선의 근사치&lt;br /&gt;
SELECT MIN(begin_time) AS oldest_stat_time,&lt;br /&gt;
       SYSDATE - MIN(begin_time) AS &amp;quot;간격(일 단위 소수)&amp;quot;,&lt;br /&gt;
       (SYSDATE - MIN(begin_time)) * 24 AS &amp;quot;약 몇 시간 전까지&amp;quot;&lt;br /&gt;
FROM v$undostat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 주의: 이건 &amp;quot;통계가 기록된 범위&amp;quot;일 뿐이며, 실제 UNDO 데이터가 남아있는지는 별도 확인이 필요합니다 (아래 4번 참고).&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1763</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1763"/>
		<updated>2026-09-08T02:11:56Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 복구 가능한 시간을 확인 하는법 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1762</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1762"/>
		<updated>2026-09-08T02:11:44Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 복구 가능한 시간을 확인 하는법 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
::::* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1761</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1761"/>
		<updated>2026-09-08T02:11:27Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
:::# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
:::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1760</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1760"/>
		<updated>2026-09-08T02:10:49Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
=== 복구 가능한 시간을 확인 하는법 ===&lt;br /&gt;
# UNDO_RETENTION 파라미터 확인 (1차 판단 기준)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 현재 설정된 목표 보존 시간(초) 확인&lt;br /&gt;
SHOW PARAMETER UNDO_RETENTION;&lt;br /&gt;
&lt;br /&gt;
SELECT name, value &lt;br /&gt;
FROM v$parameter &lt;br /&gt;
WHERE name = &#039;undo_retention&#039;;&lt;br /&gt;
-- 예: 900 (초) = 15분&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
:* 중요: 이 값은 &amp;quot;목표(target)&amp;quot;일 뿐, 보장(guarantee)이 아닙니다. 실제로는 UNDO 테이블스페이스 공간이 부족하면 이 값보다 짧게 유지될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1759</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1759"/>
		<updated>2026-09-08T02:06:26Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1758</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1758"/>
		<updated>2026-09-08T02:06:13Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1757</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1757"/>
		<updated>2026-09-08T02:06:00Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
:&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1756</id>
		<title>오라클 flashback</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_flashback&amp;diff=1756"/>
		<updated>2026-09-08T02:05:47Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: ==FLASHBACK== ===플래쉬백 개요===  ===플래쉬백 항목별 원리=== &amp;lt;source&amp;gt; Flashback 기술별 근본 원리 차이 ├── Flashback Query / Flashback Table │   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존 │ ├── Flashback Drop (Recycle Bin) │   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음 │ ├── Flashback Database │   └── Flashback Log 기반 (...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==FLASHBACK==&lt;br /&gt;
===플래쉬백 개요===&lt;br /&gt;
&lt;br /&gt;
===플래쉬백 항목별 원리===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Flashback 기술별 근본 원리 차이&lt;br /&gt;
├── Flashback Query / Flashback Table&lt;br /&gt;
│   └── UNDO 세그먼트 기반 → UNDO_RETENTION + UNDO 공간에 의존&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Drop (Recycle Bin)&lt;br /&gt;
│   └── 시간 무관, 공간 압박 시 자동 purge → &amp;quot;몇 시간&amp;quot;이라는 개념 자체가 없음&lt;br /&gt;
│&lt;br /&gt;
├── Flashback Database&lt;br /&gt;
│   └── Flashback Log 기반 (별도 로그) → DB_FLASHBACK_RETENTION_TARGET&lt;br /&gt;
│&lt;br /&gt;
└── Flashback Data Archive (FDA)&lt;br /&gt;
    └── 별도 아카이브 테이블스페이스 → 설정한 정책대로 (년 단위도 가능)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1755</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1755"/>
		<updated>2026-09-07T05:53:37Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 아키텍처 차이&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! BasicFile (Legacy) !! SecureFile (Modern)&lt;br /&gt;
|-&lt;br /&gt;
| 저장 구조 || 고정 청크 기반|| 가변 블록 + B-Tree 유사 구조&lt;br /&gt;
|-&lt;br /&gt;
| 압축 || 불가 || COMPRESS 옵션 지원&lt;br /&gt;
|-&lt;br /&gt;
| 중복제거 || 불가 || DEDUPLICATE 지원&lt;br /&gt;
|-&lt;br /&gt;
| 암호화 || 불가 || ENCRYPT 지원&lt;br /&gt;
|-&lt;br /&gt;
| 성능 || 불가  || 대폭 개선 (특히 순차 접근)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]   -- SecureFile 전용 기능&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES -- 동일 LOB 데이터 중복 제거 선택&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 || SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
:* 소량/빈번 접근 LOB: CACHE (예: 사용자 프로필 이미지 썸네일)&lt;br /&gt;
:* 대량/1회성 접근 LOB: NOCACHE (예: 로그 파일, 대용량 첨부파일)&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB과 트랜잭션 - Locator의 실체 ===&lt;br /&gt;
* LOB Locator 내부 구조 (개념적)&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB Locator = {&lt;br /&gt;
    LOB Type (CLOB/BLOB/BFILE)&lt;br /&gt;
    LOB Length&lt;br /&gt;
    Chunk Size&lt;br /&gt;
    Position (현재 커서 위치 - 세션 내에서만 유효)&lt;br /&gt;
    ... (내부 메타데이터)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 함정: LOB Locator의 생명주기&lt;br /&gt;
** 잘못된 사용 예 - LOB Locator를 커밋 후 재사용&lt;br /&gt;
**:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT doc INTO l_clob FROM lob_test WHERE id=1;&lt;br /&gt;
    COMMIT;  -- ← 이 시점 이후 l_clob 사용 시 위험할 수 있음&lt;br /&gt;
    DBMS_LOB.READ(l_clob, ...);  -- ORA-22990 가능성&lt;br /&gt;
END;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 원리: LOB Locator는 트랜잭션과 밀접하게 연관되어 있으며, 특정 상황(특히 원격 LOB이나 트랜잭션 경계를 넘는 경우)에서 무효화될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
=== LOB 실전 튜닝 포인트 ===&lt;br /&gt;
1. Fragmentation 확인&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT segment_name, bytes/1024/1024 MB, blocks&lt;br /&gt;
FROM dba_segments &lt;br /&gt;
WHERE segment_name IN (SELECT segment_name FROM dba_lobs WHERE table_name=&#039;X&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. In-row vs Out-row 비율 확인 (실제 데이터 분포)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT &lt;br /&gt;
    CASE WHEN LENGTHB(doc) &amp;lt;= 4000 THEN &#039;IN_ROW_CANDIDATE&#039; &lt;br /&gt;
         ELSE &#039;OUT_ROW&#039; END,&lt;br /&gt;
    COUNT(*)&lt;br /&gt;
FROM lob_test&lt;br /&gt;
GROUP BY CASE WHEN LENGTHB(doc) &amp;lt;= 4000 THEN &#039;IN_ROW_CANDIDATE&#039; &lt;br /&gt;
              ELSE &#039;OUT_ROW&#039; END;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Chunk 사용 효율성 (파편화 여부)&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, chunk &lt;br /&gt;
FROM user_lobs;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1754</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1754"/>
		<updated>2026-09-07T05:50:18Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* SecureFile vs BasicFile */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 아키텍처 차이&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! BasicFile (Legacy) !! SecureFile (Modern)&lt;br /&gt;
|-&lt;br /&gt;
| 저장 구조 || 고정 청크 기반|| 가변 블록 + B-Tree 유사 구조&lt;br /&gt;
|-&lt;br /&gt;
| 압축 || 불가 || COMPRESS 옵션 지원&lt;br /&gt;
|-&lt;br /&gt;
| 중복제거 || 불가 || DEDUPLICATE 지원&lt;br /&gt;
|-&lt;br /&gt;
| 암호화 || 불가 || ENCRYPT 지원&lt;br /&gt;
|-&lt;br /&gt;
| 성능 || 불가  || 대폭 개선 (특히 순차 접근)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]   -- SecureFile 전용 기능&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES -- 동일 LOB 데이터 중복 제거 선택&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 || SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
:* 소량/빈번 접근 LOB: CACHE (예: 사용자 프로필 이미지 썸네일)&lt;br /&gt;
:* 대량/1회성 접근 LOB: NOCACHE (예: 로그 파일, 대용량 첨부파일)&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB과 트랜잭션 - Locator의 실체 ===&lt;br /&gt;
* LOB Locator 내부 구조 (개념적)&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB Locator = {&lt;br /&gt;
    LOB Type (CLOB/BLOB/BFILE)&lt;br /&gt;
    LOB Length&lt;br /&gt;
    Chunk Size&lt;br /&gt;
    Position (현재 커서 위치 - 세션 내에서만 유효)&lt;br /&gt;
    ... (내부 메타데이터)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 함정: LOB Locator의 생명주기&lt;br /&gt;
** 잘못된 사용 예 - LOB Locator를 커밋 후 재사용&lt;br /&gt;
**:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT doc INTO l_clob FROM lob_test WHERE id=1;&lt;br /&gt;
    COMMIT;  -- ← 이 시점 이후 l_clob 사용 시 위험할 수 있음&lt;br /&gt;
    DBMS_LOB.READ(l_clob, ...);  -- ORA-22990 가능성&lt;br /&gt;
END;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 원리: LOB Locator는 트랜잭션과 밀접하게 연관되어 있으며, 특정 상황(특히 원격 LOB이나 트랜잭션 경계를 넘는 경우)에서 무효화될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1753</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1753"/>
		<updated>2026-09-07T05:43:13Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
:* 소량/빈번 접근 LOB: CACHE (예: 사용자 프로필 이미지 썸네일)&lt;br /&gt;
:* 대량/1회성 접근 LOB: NOCACHE (예: 로그 파일, 대용량 첨부파일)&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB과 트랜잭션 - Locator의 실체 ===&lt;br /&gt;
* LOB Locator 내부 구조 (개념적)&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB Locator = {&lt;br /&gt;
    LOB Type (CLOB/BLOB/BFILE)&lt;br /&gt;
    LOB Length&lt;br /&gt;
    Chunk Size&lt;br /&gt;
    Position (현재 커서 위치 - 세션 내에서만 유효)&lt;br /&gt;
    ... (내부 메타데이터)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 핵심 함정: LOB Locator의 생명주기&lt;br /&gt;
** 잘못된 사용 예 - LOB Locator를 커밋 후 재사용&lt;br /&gt;
**:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
DECLARE&lt;br /&gt;
    l_clob CLOB;&lt;br /&gt;
BEGIN&lt;br /&gt;
    SELECT doc INTO l_clob FROM lob_test WHERE id=1;&lt;br /&gt;
    COMMIT;  -- ← 이 시점 이후 l_clob 사용 시 위험할 수 있음&lt;br /&gt;
    DBMS_LOB.READ(l_clob, ...);  -- ORA-22990 가능성&lt;br /&gt;
END;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 원리: LOB Locator는 트랜잭션과 밀접하게 연관되어 있으며, 특정 상황(특히 원격 LOB이나 트랜잭션 경계를 넘는 경우)에서 무효화될 수 있습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1752</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1752"/>
		<updated>2026-09-07T05:39:06Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* CACHE / NOCACHE / CACHE READS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
:* 소량/빈번 접근 LOB: CACHE (예: 사용자 프로필 이미지 썸네일)&lt;br /&gt;
:* 대량/1회성 접근 LOB: NOCACHE (예: 로그 파일, 대용량 첨부파일)&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1751</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1751"/>
		<updated>2026-09-07T05:38:45Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* CACHE / NOCACHE / CACHE READS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
* 소량/빈번 접근 LOB: CACHE (예: 사용자 프로필 이미지 썸네일)&lt;br /&gt;
* 대량/1회성 접근 LOB: NOCACHE (예: 로그 파일, 대용량 첨부파일)&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1750</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1750"/>
		<updated>2026-09-07T05:38:08Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;br /&gt;
&lt;br /&gt;
==== CACHE / NOCACHE / CACHE READS ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 옵션 1: CACHE&lt;br /&gt;
-- LOB 데이터를 Buffer Cache에 정상적으로 캐싱 (일반 테이블처럼)&lt;br /&gt;
CACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 2: NOCACHE (기본값)&lt;br /&gt;
-- Direct Path I/O 사용, Buffer Cache 우회&lt;br /&gt;
-- 대용량 LOB에 적합 (캐시 오염 방지)&lt;br /&gt;
NOCACHE&lt;br /&gt;
&lt;br /&gt;
-- 옵션 3: CACHE READS&lt;br /&gt;
-- 쓰기는 NOCACHE처럼, 읽기는 CACHE처럼 동작&lt;br /&gt;
CACHE READS&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1749</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1749"/>
		<updated>2026-09-07T05:36:25Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* LOB 인덱스 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
* LOB 데이터가 여러 CHUNK에 걸쳐 저장될 때, 이 청크들의 순서와 위치를 관리하는 B-Tree 기반 인덱스.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 LOB Locator (SETID + LENGTH 정보 포함)&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
LOB Index (CHUNK 순서 매핑)&lt;br /&gt;
    │&lt;br /&gt;
    ├── CHUNK 1 (위치: block#100)&lt;br /&gt;
    ├── CHUNK 2 (위치: block#105)&lt;br /&gt;
    └── CHUNK 3 (위치: block#250)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 왜 중요 한가?&lt;br /&gt;
# LOB의 부분 읽기/쓰기(Partial Read/Write) 시 이 인덱스를 통해 필요한 청크만 접근&lt;br /&gt;
# DBMS_LOB.READ(lob, amount, offset) 호출 시 인덱스를 스캔하여 offset에 해당하는 청크로 직행&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== PCTVERSION과 RETENTION (읽기 일관성) ===&lt;br /&gt;
==== 일반 테이블 vs LOB의 읽기 일관성 차이 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 구분 !! 일반 테이블 !! LOB&lt;br /&gt;
|-&lt;br /&gt;
| 메커니즘 || UNDO Segment || LOB 자체 버전 관리&lt;br /&gt;
|-&lt;br /&gt;
| 위치 || 별도 UNDO 테이블스페이스 || LOB Segment 내부&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* 핵심: LOB은 UNDO를 사용하지 않고, 자체적으로 이전 버전 데이터를 LOB 세그먼트 내에 보관합니다.&lt;br /&gt;
&lt;br /&gt;
==== PCTVERSION vs RETENTION ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
-- 방식 1: 공간 비율 기반 (전통적 방식)&lt;br /&gt;
PCTVERSION 10   -- 전체 LOB 세그먼트의 10%를 old version 유지에 사용&lt;br /&gt;
                -- 초과 시 오래된 버전부터 재사용(overwrite)&lt;br /&gt;
&lt;br /&gt;
-- 방식 2: 시간 기반 (Oracle 10g 이후 권장)&lt;br /&gt;
RETENTION       -- UNDO_RETENTION 파라미터 값을 따름&lt;br /&gt;
                -- 자동 스페이스 관리(ASSM) tablespace 필요&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 실무 팁: 대용량 LOB이 빈번히 업데이트되는 시스템에서 PCTVERSION이 너무 낮으면 ORA-22924 에러(snapshot too old 유사 현상) 발생 가능.&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1748</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1748"/>
		<updated>2026-09-07T05:29:38Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* CHUNK 설계 원칙 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&amp;lt;/source&amp;gt;&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#:&amp;lt;source&amp;gt; CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1747</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1747"/>
		<updated>2026-09-07T05:29:06Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* CHUNK 단위 저장 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
==== CHUNK 설계 원칙 ====&lt;br /&gt;
&lt;br /&gt;
# 소량 다건 CLOB (예: 짧은 메모, 코멘트)&lt;br /&gt;
#: CHUNK 8192   -- DB_BLOCK_SIZE와 동일하게&lt;br /&gt;
# 대용량 CLOB (예: 문서, XML)&lt;br /&gt;
#: CHUNK 32768  -- 더 크게 설정하여 I/O 효율 극대화&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1746</id>
		<title>오라클 LOB 데이터 구조</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%98%A4%EB%9D%BC%ED%81%B4_LOB_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EA%B5%AC%EC%A1%B0&amp;diff=1746"/>
		<updated>2026-09-07T05:27:41Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* CHUNK 단위 저장 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LOB(BLOB/CLOB)대용량 데이터 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
LOB(BLOB/CLOB)이 대용량 데이터를 저장하는 핵심 원리는 &#039;&#039;&#039;&amp;quot;포인터(로케이터) + 별도 세그먼트 분리 저장&amp;quot;&#039;&#039;&#039; 구조&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
LOB&lt;br /&gt;
├── Internal LOB (DB 내부 저장)&lt;br /&gt;
│   ├── CLOB (Character LOB) - 문자 데이터&lt;br /&gt;
│   ├── NCLOB (National CLOB) - 다국어 문자셋&lt;br /&gt;
│   └── BLOB (Binary LOB) - 바이너리 데이터&lt;br /&gt;
└── External LOB&lt;br /&gt;
    └── BFILE - OS 파일시스템 참조 (읽기 전용)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== CLOB vs VARCHAR2 근본적 차이 ====&lt;br /&gt;
# VARCHAR2: 최대 32767 bytes (PL/SQL , 19c 이상부터 SQL도 가능), 4000 bytes (SQL) - inline storage 강제&lt;br /&gt;
# CLOB: 최대 4GB * DB_BLOCK_SIZE (이론상 128TB) - out-of-line storage 가능&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 저장 구조 (핵심) ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
Table Row&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB LOCATOR │ ← 테이블 로우에 실제 저장되는 것 (포인터/핸들)&lt;br /&gt;
│ (약 4KB↓)   │&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB INDEX   │ ← LOB 청크들을 관리하는 B-Tree 인덱스&lt;br /&gt;
└─────────────┘&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
┌─────────────┐&lt;br /&gt;
│ LOB SEGMENT │ ← 실제 데이터가 저장되는 세그먼트 (CHUNK 단위)&lt;br /&gt;
└─────────────┘&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== LOB 로케이터(LOCATOR) ===&lt;br /&gt;
# 테이블 로우에는 실제 데이터가 아니라 LOB 데이터를 가리키는 40바이트 내외의 로케이터(포인터)만 저장됨&lt;br /&gt;
# 실제 데이터는 별도의 LOB 세그먼트에 존재하고, 애플리케이션은 이 로케이터를 통해 스트리밍 방식(READ/WRITE by chunk)으로 데이터에 접근함&lt;br /&gt;
&lt;br /&gt;
=== In-row vs Out-of-row ===&lt;br /&gt;
:- 데이터 크기가 작으면(기본 임계값 관련, ENABLE STORAGE IN ROW) 로우 내부에 직접 저장&lt;br /&gt;
:- 임계값을 넘으면 별도의 LOB 세그먼트(out-of-row)에 체인 형태로 저장되고 로우에는 포인터만 남음&lt;br /&gt;
:- 이 덕분에 4000바이트 제한을 가진 VARCHAR2/RAW와 달리 최대 4GB(BasicFile) ~ (LOB) 단위까지 저장 가능&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
CLOB 데이터 크기 확인&lt;br /&gt;
    │&lt;br /&gt;
    ├── 4000 bytes 이하 (기본값)&lt;br /&gt;
    │   └── ENABLE STORAGE IN ROW&lt;br /&gt;
    │       → 로우 내부에 직접 저장 (Inline)&lt;br /&gt;
    │       → LOB Locator + 실제 데이터가 로우에 존재&lt;br /&gt;
    │&lt;br /&gt;
    └── 4000 bytes 초과 (또는 DISABLE STORAGE IN ROW)&lt;br /&gt;
        └── OUT OF ROW 강제 이동&lt;br /&gt;
            → 로우에는 LOB Locator만 존재&lt;br /&gt;
            → 실제 데이터는 별도 LOB Segment에 저장&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 저장 방식 확인 테스트&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
CREATE TABLE lob_test (&lt;br /&gt;
    id NUMBER,&lt;br /&gt;
    doc CLOB&lt;br /&gt;
) LOB (doc) STORE AS (&lt;br /&gt;
    ENABLE STORAGE IN ROW    -- 4000바이트 이하는 인라인&lt;br /&gt;
    CHUNK 8192                -- 청크 크기&lt;br /&gt;
    PCTVERSION 10              -- 버전 유지 비율&lt;br /&gt;
    NOCACHE                    -- 버퍼캐시 사용 안함&lt;br /&gt;
    LOGGING&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 성능 함정: 4000바이트 근처의 데이터가 빈번하게 업데이트되면 in-row ↔ out-of-row 전환이 발생하여 Row Migration과 유사한 오버헤드 발생.&lt;br /&gt;
&lt;br /&gt;
=== CHUNK 단위 저장 ===&lt;br /&gt;
# LOB 세그먼트는 내부적으로 CHUNK(기본 8KB, 블록 사이즈 배수) 단위로 분할 저장. &lt;br /&gt;
# 큰 데이터를 CHUNK들의 연결 리스트로 관리하기 때문에 부분 읽기/쓰기(random access)가 가능하고, 전체를 메모리에 올리지 않고도 스트리밍 처리가 가능.&lt;br /&gt;
&lt;br /&gt;
* CHUNK란?&lt;br /&gt;
** LOB 데이터의 최소 I/O 단위&lt;br /&gt;
** DB_BLOCK_SIZE의 배수여야 함 (기본값: DB_BLOCK_SIZE, 최대 32KB 권장)&lt;br /&gt;
** 하나의 CHUNK는 여러 Oracle Block으로 구성 가능하나, 하나의 익스텐트 내에 존재&lt;br /&gt;
&lt;br /&gt;
=== LOB 인덱스 ===&lt;br /&gt;
LOB 세그먼트의 CHUNK 위치를 추적하기 위해 별도의 LOB 인덱스가 존재합니다(B-tree 구조로 CHUNK 매핑 관리).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== LOB 세그먼트 정보 확인 ===&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT table_name, column_name, segment_name, index_name,&lt;br /&gt;
       chunk, pctversion, cache, logging, in_row&lt;br /&gt;
  FROM user_lobs -- dba_lobs&lt;br /&gt;
 WHERE table_name = &#039;YOUR_TABLE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== SecureFile vs BasicFile ===&lt;br /&gt;
:- BasicFile: 전통적 방식, LOB 세그먼트에 체인 저장&lt;br /&gt;
:- SecureFile(11g+): ASSM 기반, 압축/중복제거/암호화 지원, 성능 개선된 구조로 대부분 권장&lt;br /&gt;
&lt;br /&gt;
즉, &amp;quot;행 안에 다 넣지 않고 별도 세그먼트에 청크 단위로 분산 저장 + 로케이터로 참조&amp;quot;하는 것이 대용량 저장의 핵심 메커니즘입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
# Oracle 19c LOB 저장 속성 정리&lt;br /&gt;
&lt;br /&gt;
## LOB STORAGE 절 기본 구조&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
LOB (column_name) STORE AS [SECUREFILE|BASICFILE] [lob_segment_name]&lt;br /&gt;
(&lt;br /&gt;
  TABLESPACE ...&lt;br /&gt;
  ENABLE|DISABLE STORAGE IN ROW&lt;br /&gt;
  CHUNK n&lt;br /&gt;
  PCTVERSION n | RETENTION [AUTO|MAX n|MIN n]&lt;br /&gt;
  FREEPOOLS n&lt;br /&gt;
  CACHE | NOCACHE | CACHE READS&lt;br /&gt;
  LOGGING | NOLOGGING&lt;br /&gt;
  COMPRESS [LOW|MEDIUM|HIGH]&lt;br /&gt;
  DEDUPLICATE | KEEP_DUPLICATES&lt;br /&gt;
  ENCRYPT ... | DECRYPT&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 속성별 정리&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 캡션 텍스트&lt;br /&gt;
|-&lt;br /&gt;
! 속성 !! 설명 !! 비고 &lt;br /&gt;
|-&lt;br /&gt;
| **SECUREFILE / BASICFILE** || LOB 저장 방식 선택 &lt;br /&gt;
|| SecureFile 권장(기본값은 DB_SECUREFILE 파라미터에 따름) &lt;br /&gt;
|-&lt;br /&gt;
| **ENABLE/DISABLE STORAGE IN ROW** || 로우 내 인라인 저장 여부 || 임계값 이하 데이터는 IN ROW 저장 &lt;br /&gt;
|-&lt;br /&gt;
| **CHUNK** || LOB 저장 최소 단위(바이트) || 블록사이즈 배수, 기본 8K&lt;br /&gt;
|-&lt;br /&gt;
| **PCTVERSION** || (BasicFile 전용) 이전 버전 유지 공간 % || Undo 방식과 다른 read consistency &lt;br /&gt;
|-&lt;br /&gt;
| **RETENTION [AUTO/MAX/MIN]** || (SecureFile 전용) 버전 보존 정책 || AUTO가 일반적 &lt;br /&gt;
|-&lt;br /&gt;
| **CACHE / NOCACHE / CACHE READS** || 버퍼캐시 사용 여부 || 대용량은 보통 NOCACHE &lt;br /&gt;
|-&lt;br /&gt;
| **LOGGING / NOLOGGING** || Redo 생성 여부 || 대량 초기 적재시 NOLOGGING 고려 &lt;br /&gt;
|-&lt;br /&gt;
| **COMPRESS [LOW/MEDIUM/HIGH]** || (SecureFile 전용) 압축 레벨 || ACO(Advanced Compression) 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **DEDUPLICATE / KEEP_DUPLICATES** || (SecureFile 전용) 중복 제거 || ACO 라이선스 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **ENCRYPT / DECRYPT** || (SecureFile 전용) 투명 암호화 | TDE 필요 &lt;br /&gt;
|-&lt;br /&gt;
| **FREEPOOLS** || (SecureFile 전용) 동시성 향상용 free space pool 분리 || RAC 환경 동시 write 성능 &lt;br /&gt;
|}&lt;br /&gt;
## 🆕 19c 관련 New Feature / 변경사항&lt;br /&gt;
&lt;br /&gt;
**1. `DB_SECUREFILE` 파라미터 기본값 변경 없음, 단 SecureFile이 사실상 표준화**&lt;br /&gt;
- 12c부터 BasicFile은 &amp;quot;desupported&amp;quot;(deprecated) 상태 유지, 19c에서도 동일하게 BasicFile은 신규 개발에 비권장&lt;br /&gt;
&lt;br /&gt;
**2. LOB 관련 초기화 파라미터 정리 지속**&lt;br /&gt;
- `DB_SECUREFILE` 파라미터 값: `PERMITTED`(기본), `ALWAYS`, `FORCE`, `NEVER`, `IGNORE`&lt;br /&gt;
- 19c에서도 동일 옵션 유지, ALWAYS/FORCE 사용시 BasicFile 문법도 자동으로 SecureFile로 생성&lt;br /&gt;
&lt;br /&gt;
**3. JSON 관련 LOB 활용 강화 (19c 특징)**&lt;br /&gt;
- 19c의 확장된 JSON 지원(다중 JSON 컬럼, 부분 업데이트 등)이 내부적으로 SecureFile LOB 기반으로 동작 — LOB 자체의 새 절이라기보다는 LOB을 활용하는 상위 기능 확장&lt;br /&gt;
&lt;br /&gt;
**4. In-Memory 관련**&lt;br /&gt;
- 19c에서 `INMEMORY` 절은 LOB 자체에는 직접 적용 불가(LOB은 IM 컬럼 스토어 미지원) — 이 제약은 계속 유지됨(신규 아님, 혼동 주의사항으로 정리)&lt;br /&gt;
&lt;br /&gt;
**참고**: 19c 자체에서 LOB STORE AS 문법 자체에 **완전히 새로운 키워드가 추가된 것은 없고**, 12c~18c에서 도입된 SecureFile 관련 옵션들이 19c에서도 그대로 유지·강화되는 흐름입니다. 12c 이후 큰 변화는 없었고, 오히려 &amp;quot;BasicFile 지양, SecureFile 표준화&amp;quot;라는 정책적 방향이 19c에서 더 굳어진 것으로 보시면 됩니다.&lt;br /&gt;
&lt;br /&gt;
특정 옵션(예: COMPRESS, DEDUPLICATE의 라이선스 조건이나 RAC FREEPOOLS 튜닝)에 대해 더 깊게 필요하시면 말씀해주세요.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
</feed>