oracle lob의 기능 중. deduplicate(중복제거)와 compress(압축)기능이 있습니다.
securefile형태에서 사용가능한 기능입니다.
deduplicate(중복제거)
동일한 lob데이터를 한번만 저장하고 포인터로 저장하는 매커니즘입니다.
Secure hash index를 사용하여 모든 lob 데이터의 해시값을 계산하고 동일한 내용이면 포인터만 저장합니다.
실제로 1000개 행에 동일한 100kb이미지를 저장한다고 했을때 동작과정은 아래와같습니다.
1. 1 row insert
- 한개 row의 image hash값 계산하여 secure hash index에 등록
- 100kb 데이터 저장
2.동일 이미지 insert
- index조회하여 동일 hash값인거 확인 후 포인터(8bytes)만 저장
3. 999번 반복
특징
읽기 성능
- 결과는 동일하며 포인터 -> 원본위치로 이동시 1회 추가 i/o 필요
쓰기 성능
- 포인터만 저장하므로 극정으로 향상
- hash 계산 오버헤드는 최소화
복사 성능
- 원본데이터 공유하여 포인터만 복사하기때문에 성능이 크게 향상(10배 이상)
compress(압축)
개별 lob object를 압축 알고리즘으로 축소하는 매커니즘입니다.
단위는 (low/medium/high)세가지가 있습니다.
low - CPU를 최대 3배 적게사용하며 압축률은 medium 대비 80%의 압축률 낮은 특징이 있음.
medium(default) - 일반적인 용도로 사용.CPU 오버헤드 3~5%
high - CPU 오버헤드 최고이며 압축률도 최고
Oracle 23ai부터는 deduplicate 활성화 전 효과를 측정할 수 있습니다.
DBMS_LOB.GET_LOB_DEDUPLICATION_RATIO
테스트를 통해 절감효과를 확인해보겠습니다.
테스트테이블 생성 스크립트
B(BLOB)과 C(CLOB)으 포함된 테이블이고 파티션테이블로 생성하였습니다.
DROP TABLE LOB_TEST PURGE;
CREATE TABLE YSBAE.LOB_TEST
(
A VARCHAR2(10),
B BLOB,
C CLOB,
D VARCHAR2(4000)
)
TABLESPACE USERS
NOLOGGING
LOB (B) STORE AS SECUREFILE
(
STORAGE
(
INITIAL 8M
NEXT 1M
)
CHUNK 8192
PCTVERSION 0
)
LOB (C) STORE AS SECUREFILE
(
STORAGE
(
INITIAL 8M
NEXT 1M
)
CHUNK 8192
PCTVERSION 0
)
PARTITION BY RANGE (A)
(
PARTITION PT_LOB_TEST_01 VALUES LESS THAN ('20250101')
TABLESPACE USERS
STORAGE
(
INITIAL 1M
NEXT 1M
)
NOLOGGING
NOCOMPRESS
LOB (B) STORE AS
(
TABLESPACE USERS
CHUNK 8192
PCTVERSION 0
)
LOB (C) STORE AS
(
TABLESPACE USERS
CHUNK 8192
PCTVERSION 0
)
,
PARTITION PT_LOB_TEST_02 VALUES LESS THAN ('20250201')
TABLESPACE USERS
STORAGE
(
INITIAL 1M
NEXT 1M
)
NOLOGGING
NOCOMPRESS
LOB (B) STORE AS
(
TABLESPACE USERS
CHUNK 8192
PCTVERSION 0
)
LOB (C) STORE AS
(
TABLESPACE USERS
CHUNK 8192
PCTVERSION 0
)
);
deduplicate 테스트
테이블 생성 직후 메타데이터 확인
select
table_name,column_name,lob_name,partition_name,lob_partition_name,IN_ROW,compression,deduplication,securefile
--*
From dba_lob_partitions where table_name='LOB_TEST'
TABLE_NAME COLUMN_NAME LOB_NAME PARTITION_NAME LOB_PARTITION_NAME IN_ROW COMPRESSION DEDUPLICATION SECUREFILE
------------ -------------- ---------------------------- ---------------- ------------------- ------- ----------- --------------- ----------
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_01 SYS_LOB_P81972 YES NO NO YES
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_02 SYS_LOB_P81973 YES NO NO YES
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_01 SYS_LOB_P81976 YES NO NO YES
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_02 SYS_LOB_P81977 YES NO NO YES
select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480436C00002$$','SYS_LOB0000480436C00003$$');
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE BLOCKS MB
---------- ------------------------------ ------------------ ------------------ --------- ---------
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 128 1
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81977 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81976 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81973 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81972 LOB PARTITION 1024 8
1.2000건의 데이터를 삽입 후 용량변화 체크
BEGIN
FOR i in 1..2000
LOOP
INSERT INTO LOB_TEST VALUES('20250101',xmlserialize(content xmltype(to_clob('<x>')||lpad('X',4000,'X')||lpad('X',4000,'X')||'</x>') as blob),to_clob(lpad('a',4000,'a')),DBMS_RANDOM.STRING('B',4000));
END LOOP;
COMMIT;
END;
/
2.용량 확인
B,C 컬럼 둘다 blocks(1024 -> 3072) , MB(8 -> 24)로 증가된것을 확인할 수 있음.
select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480436C00002$$','SYS_LOB0000480436C00003$$');
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE BLOCKS MB
----------- ------------------------------ ---------------- ------------------ --------- ---------
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 2048 16 <--
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81977 LOB PARTITION 3072 24 <-- PT_LOB_TEST_02(C) 컬럼의 lob 값
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81976 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81973 LOB PARTITION 3072 24 <-- PT_LOB_TEST_02(B) 컬럼의 lob 값
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81972 LOB PARTITION 1024 8
3.deduplicate명령어
ALTER TABLE LOB_TEST MODIFY PARTITION PT_LOB_TEST_02 LOB(B) (deduplicate);
ALTER TABLE LOB_TEST MODIFY PARTITION PT_LOB_TEST_02 LOB(C) (deduplicate);
기존에 데이터가 있는 상태에서 확인시 오히려 blocks와 MB가 더 늘어난 것을 확인할 수 있습니다.
SQL> select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480436C00002$$','SYS_LOB0000480436C00003$$');
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE BLOCKS MB
------ --------------------------- ---------------- ------------------ --------- ---------
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 2048 16
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81977 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(C) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81976 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81973 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(B) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81972 LOB PARTITION 1024 8
SQL> select
table_name,column_name,lob_name,partition_name,lob_partition_name,IN_ROW,compression,deduplication,securefile
--*
From dba_lob_partitions where table_name='LOB_TEST';
TABLE_NAME COLUMN_NAME LOB_NAME PARTITION_NAME LOB_PARTITION_NAME IN_ROW COMPRESSION DEDUPLICATION SECUREFILE
------------ -------------- --------------------------- ------------------ --------------------- ------- ----------- --------------- ----------
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_01 SYS_LOB_P81972 YES NO NO YES
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_02 SYS_LOB_P81973 YES NO LOB YES <--deduplication 컬럼이 NO 에서 LOB으로 변경
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_01 SYS_LOB_P81976 YES NO NO YES
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_02 SYS_LOB_P81977 YES NO LOB YES <--deduplication 컬럼이 NO 에서 LOB으로 변경
4 rows selected.
해당 상태에서 다시 2000건 삽입후 용량 비교
BEGIN
FOR i in 1..2000
LOOP
INSERT INTO LOB_TEST VALUES('20250101',xmlserialize(content xmltype(to_clob('<x>')||lpad('X',4000,'X')||lpad('X',4000,'X')||'</x>') as blob),to_clob(lpad('a',4000,'a')),DBMS_RANDOM.STRING('B',4000));
END LOOP;
COMMIT;
END;
/
2000 -> 4000건으로 늘었지만, block수는 B와 C 모두 4096에서 변화없음.
(포인터만 입력되서 실제 데이터는 늘어나지 않는것으로 판단)
select count(*) from lob_test;
4000
SQL> select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480436C00002$$','SYS_LOB0000480436C00003$$');
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE BLOCKS MB
------ --------------------------- ---------------- ------------------ --------- ---------
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 4096 32
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81977 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(C) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81976 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81973 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(B) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81972 LOB PARTITION 1024 8
+2000건 추가 후 확인
BEGIN
FOR i in 1..2000
LOOP
INSERT INTO LOB_TEST VALUES('20250101',xmlserialize(content xmltype(to_clob('<x>')||lpad('X',4000,'X')||lpad('X',4000,'X')||'</x>') as blob),to_clob(lpad('a',4000,'a')),DBMS_RANDOM.STRING('B',4000));
END LOOP;
COMMIT;
END;
/
2000건 추가하여도 마찬가지로 블록의 변화는 없음
select count(*) from lob_test;
6000
SQL> select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480436C00002$$','SYS_LOB0000480436C00003$$');
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE BLOCKS MB
------ --------------------------- ---------------- ------------------ --------- ---------
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 6144 48
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81977 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(C) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00003$$ SYS_LOB_P81976 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81973 LOB PARTITION 4096 32 <-- PT_LOB_TEST_02(B) 컬럼의 lob 값 dedupulicate 후에 늘어남.
YSBAE SYS_LOB0000480436C00002$$ SYS_LOB_P81972 LOB PARTITION 1024 8
결론. deduplicate옵션은 새로 들어올 데이터에 대해서 적용되는것으로 판단되며, 기존에 있는데이터에서 적용시 오히려 용량이 늘어나는 모습을 보임
compress 테스트
위의 상황에서 두 컬럼에 대해서 압축을 시도하고 용량이 얼마나 주는지 체크
high 옵션사용하여 테스트를 진행하였습니다.
ALTER TABLE LOB_TEST MOVE PARTITION PT_LOB_TEST_02 LOB(C) STORE AS SECUREFILE (TABLESPACE USERS
COMPRESS HIGH
) UPDATE INDEXES;
ALTER TABLE LOB_TEST MOVE PARTITION PT_LOB_TEST_02 LOB(B) STORE AS SECUREFILE (TABLESPACE USERS
COMPRESS HIGH
) UPDATE INDEXES;
확인
SQL> select
table_name,column_name,lob_name,partition_name,lob_partition_name,IN_ROW,compression,deduplication,securefile
--*
From dba_lob_partitions where table_name='LOB_TEST';
TABLE_NAME COLUMN_NAME LOB_NAME PARTITION_NAME LOB_PARTITION_NAME IN_ROW COMPRESSION DEDUPLICATION SECUREFILE
------------ -------------- --------------------------- ------------------ --------------------- ------- ----------- --------------- ----------
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_01 SYS_LOB_P81972 YES NO NO YES
LOB_TEST B SYS_LOB0000480436C00002$$ PT_LOB_TEST_02 SYS_LOB_P81973 YES HIGH LOB YES <--compression 컬럼이 NO 에서 high으로 변경
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_01 SYS_LOB_P81976 YES NO NO YES
LOB_TEST C SYS_LOB0000480436C00003$$ PT_LOB_TEST_02 SYS_LOB_P81977 YES HIGH LOB YES <--compression 컬럼이 NO 에서 high으로 변경
4 rows selected.
select owner,segment_name,partition_name,segment_type,blocks,bytes/1024/1024 as MB
from dba_segments where segment_name in ('LOB_TEST','SYS_LOB0000480499C00002$$','SYS_LOB0000480499C00003$$');
YSBAE LOB_TEST PT_LOB_TEST_01 TABLE PARTITION 128 1
YSBAE SYS_LOB0000480499C00002$$ SYS_LOB_P82062 LOB PARTITION 1024 8 <--PT_LOB_TEST_02(B) 용량이 줌
YSBAE SYS_LOB0000480499C00003$$ SYS_LOB_P82056 LOB PARTITION 1024 8
YSBAE SYS_LOB0000480499C00002$$ SYS_LOB_P82052 LOB PARTITION 1024 8
YSBAE LOB_TEST PT_LOB_TEST_02 TABLE PARTITION 6144 48
YSBAE SYS_LOB0000480499C00003$$ SYS_LOB_P82060 LOB PARTITION 1024 8 <--PT_LOB_TEST_02(C) 용량이 줌
;
결론 : 압축 시 용량이 압축률로 인해 신규생성 직후의 블록수만큼의 크기로 줄어듬
매커니즘은 다르지만 각 옵션을 사용하면 lob의 용량을 적절하게 관리를 할 수 있을 것 같습니다.
출처 : https://docs.oracle.com/en/database/oracle/oracle-database/18/adlob/using-oracle-LOBs-storage.html
Database SecureFiles and Large Objects Developer's Guide
Oracle LOB storage has two types, SecureFiles LOB storage and BasicFiles LOB storage, which are used with different types of tablespaces.
docs.oracle.com
'Oracle > 운영' 카테고리의 다른 글
| Delayed block cleanout 발생과 해결법 (0) | 2026.01.06 |
|---|---|
| ORA-01450: Maximum Key Length (6398) Exceeded (3) | 2025.12.19 |
| [unused 와 drop column]컬럼 삭제 매커니즘과 각 명령어 수행 시 용량 비교 (0) | 2025.12.10 |
| data type을 확인하는 dump 함수 사용법 (0) | 2025.10.30 |
| lob 컬럼 move tablespace 명령어 (0) | 2025.07.17 |
댓글