LOB 타입
오라클에서 네 가지 LOB타입을 지원
- CLOB : 문자 LOB, XML또는 일반문장과 같은 문자 정보를 대량으로 저장
- NCLOB: 문자 LOB, CLOB과 같으나 내셔널 케릭터 셋
- BLOB : 이진 LOB, 워드, 이미지 이진정보를 저장
- BFILE : 이진 파일 LOB, 파일에 대한 포인터 일기모드만 접근 가능
내부 LOB
SQL> DROP TABLE T;
Table dropped.
SQL>
SQL> CREATE TABLE T
2 (
3 ID INT PRIMARY KEY,
4 TXT CLOB
5 );
Table created.
SQL> SELECT DBMS_METADATA.GET_DLL('TABLE','T');
SELECT DBMS_METADATA.GET_DLL('TABLE','T')
*
ERROR at line 1:
ORA-00923: FROM keyword not found where expected
SQL> SELECT DBMS_METADATA.GET_DLL('TABLE','T') FROM DUAL;
SELECT DBMS_METADATA.GET_DLL('TABLE','T') FROM DUAL
*
ERROR at line 1:
ORA-00904: "DBMS_METADATA"."GET_DLL": invalid identifier
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','T') FROM DUAL;
DBMS_METADATA.GET_DDL('TABLE','T')
--------------------------------------------------------------------------------
'CREATE TABLE "BSHMAN"."T"
( "ID" NUMBER(*,0),
"TXT" CLOB,
PRIMARY KEY ("ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "USERS" ENABLE
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "USERS"
LOB ("TXT") STORE AS BASICFILE (
TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTION
NOCACHE LOGGING )'
--LOB의 주요속성(테이블스페이스, STORAGE IN ROW, CHUNK 8192, RETENTION, NOCACHE, STORAGE 절)
-- 멀티 세크먼트
SQL> SELECT SEGMENT_NAME, SEGMENT_TYPE
2 FROM USER_SEGMENTS;
SEGMENT_NAME SEGMENT_TYPE
------------------------------ ------------------------------------
A TABLE
BIN$V0XPJ2kWRXeXkMio4Pes/Q==$0 TABLE
SOURCE TABLE
DR$SOURCE_IDX$I TABLE
DR$SOURCE_IDX$R TABLE
SYS_IL0000075319C00006$$ LOBINDEX
SYS_IOT_TOP_75322 INDEX
SYS_IL0000075324C00002$$ LOBINDEX
SYS_IOT_TOP_75327 INDEX
DR$SOURCE_IDX$X INDEX
SYS_LOB0000075319C00006$$ LOBSEGMENT
SYS_LOB0000075324C00002$$ LOBSEGMENT
12 rows selected.
-- LOBINDEX : LOB을 찾기위해 사용
-- LOBSEGMENT : 실제 데이터가 저장되는 공간
LOB 테이블스페이스
- 실제 테이블 데이터를 저장하는 테이블스페이스와 관리적인 측면과 성능적인 측면으로 다를 수 있다.
- 버퍼 캐쉬에 캐쉬되지 않는다.
- LOB 액세스는 디스크에서 DIRECT READ나 디스크에 DIRECT WRITE 등 물리적 I/O가 발생
IN ROW 절
SQL> DROP TABLE T;
Table dropped.
SQL>
SQL> CREATE TABLE T
2 (
3 ID INT PRIMARY KEY,
4 IN_ROW CLOB,
5 OUT_ROW CLOB
6 )
7 LOB (IN_ROW) STORE AS (ENABLE STORAGE IN ROW)
8 LOB (OUT_ROW) STORE AS (DISABLE STORAGE IN ROW)
9 ;
Table created.
SQL> DROP TABLE T;
Table dropped.
Elapsed: 00:00:00.37
-- 테이블에 길이가 4,000바이트 미만인 문자열 데이터를 입력
SQL> CREATE TABLE T
2 (
3 ID INT PRIMARY KEY,
4 IN_ROW CLOB,
5 OUT_ROW CLOB
6 )
7 LOB (IN_ROW) STORE AS (ENABLE STORAGE IN ROW)
8 LOB (OUT_ROW) STORE AS (DISABLE STORAGE IN ROW);
Table created.
Elapsed: 00:00:00.12
SQL>
SQL> INSERT INTO T
2 SELECT ROWNUM
3 , OWNER || ' ' || OBJECT_NAME || ' ' || OBJECT_TYPE || ' ' || STATUS
4 , OWNER || ' ' || OBJECT_NAME || ' ' || OBJECT_TYPE || ' ' || STATUS
5 FROM ALL_OBJECTS;
71641 rows created.
Elapsed: 00:01:24.61
SQL> DECLARE
2 L_CNT NUMBER;
3 L_DATA VARCHAR2(32765);
4 BEGIN
5
6 SELECT COUNT(*)
7 INTO L_CNT
8 FROM T;
9
10 DBMS_MONITOR.SESSION_TRACE_ENABLE;
11 FOR I IN 1 .. L_CNT
12 LOOP
13 SELECT IN_ROW INTO L_DATA FROM T WHERE ID = I;
14 SELECT OUT_ROW INTO L_DATA FROM T WHERE ID = I;
15 END LOOP;
16 END;
17 /
PL/SQL procedure successfully completed.
Elapsed: 00:01:24.83
SELECT IN_ROW
FROM
T WHERE ID = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 71638 1.57 1.53 0 0 0 0
Fetch 71638 1.21 1.36 0 214914 0 71638
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 143277 2.79 2.89 0 214914 0 71638
SELECT OUT_ROW
FROM
T WHERE ID = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 71638 1.26 1.16 0 0 0 0
Fetch 71638 15.49 63.37 71638 501469 0 71638
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 143277 16.75 64.53 71638 501469 0 71638
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 91 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=0 us cost=1 size=253 card=1)
1 INDEX UNIQUE SCAN SYS_C0011335 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 75339)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
direct path read 71638 0.14 51.95
asynch descriptor resize 71638 0.00 0.14
-- IN_ROW 보다 OUT_ROW 더 많은 논리 I/O를 발생
SQL> CREATE SEQUENCE S START WITH 200000;
Sequence created.
Elapsed: 00:00:00.06
SQL> DECLARE
2 L_CNT NUMBER;
3 L_DATA VARCHAR2(32765);
4 BEGIN
5 DBMS_MONITOR.SESSION_TRACE_ENABLE;
6 FOR I IN 1 .. 100
7 LOOP
8 UPDATE T SET IN_ROW = TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') WHERE
ID = I;
9 UPDATE T SET OUT_ROW = TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') WHERE
ID = I;
10 INSERT INTO T (ID, IN_ROW) VALUES (S.NEXTVAL, 'Hello World');
11 INSERT INTO T (ID, OUT_ROW) VALUES (S.NEXTVAL, 'Hello World');
12 END LOOP;
13 END;
14 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.29
UPDATE T SET IN_ROW = TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS')
WHERE
ID = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.00 0.00 0 200 206 100
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.00 0.00 0 200 206 100
Rows Row Source Operation
------- ---------------------------------------------------
0 UPDATE T (cr=2 pr=0 pw=0 time=0 us)
1 INDEX UNIQUE SCAN SYS_C0011339 (cr=2 pr=0 pw=0 time=0 us cost=1 size=2015 card=1)(object id 75437)
UPDATE T SET OUT_ROW = TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS')
WHERE
ID = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.03 0.13 0 1499 2244 100
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.03 0.13 0 1499 2244 100
Rows Row Source Operation
------- ---------------------------------------------------
0 UPDATE T (cr=12 pr=0 pw=1 time=0 us)
1 INDEX UNIQUE SCAN SYS_C0011339 (cr=2 pr=0 pw=0 time=0 us cost=1 size=253 card=1)(object id 75437)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
Disk file operations I/O 1 0.00 0.00
direct path write 91 0.01 0.04
asynch descriptor resize 175 0.00 0.00
********************************************************************************
INSERT INTO T (ID, IN_ROW)
VALUES
(S.NEXTVAL, 'Hello World')
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.00 0 0 0 0
Execute 100 0.01 0.00 0 2 321 100
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.03 0.01 0 2 321 100
INSERT INTO T (ID, OUT_ROW)
VALUES
(S.NEXTVAL, 'Hello World')
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.01 0.07 0 1007 1531 100
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.01 0.07 0 1007 1531 100
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
direct path write 100 0.00 0.04
asynch descriptor resize 192 0.00 0.00
********************************************************************************
-- 동일한 현상 발생 기본적으로 ENABLE STORAGE IN ROW를 사용하는것이 좋음
CHUNK
- 일반적으로 가장 작은 할당 단위가 블록인데, LOB에서는 청크가 가장 작은 단위이다.
- LOB인스턴스는 적어도 하나의 청크를 사용
- LOB인스턴스당 청크의 수를 최소화할 때 주의(공간낭비를 최소화하여 적당한 크기지정)
RETENTION절
SQL> DROP TABLE T;
Table dropped.
SQL> CREATE TABLE T
2 (
3 ID INT PRIMARY KEY,
4 TXT CLOB
5 );
Table created.
SQL> INSERT INTO T VALUES(1,'HELLO WORLD');
1 row created.
SQL> COMMIT;
Commit complete.
SQL> DECLARE
2 L_CLOB CLOB;
3
4 CURSOR C IS SELECT ID FROM T;
5 L_ID NUMBER;
6 BEGIN
7 SELECT TXT INTO L_CLOB FROM T;
8 OPEN C;
9
10 UPDATE T SET ID = 2, TXT = 'GoodBye';
11 COMMIT;
12
13 DBMS_OUTPUT.PUT_LINE( DBMS_LOB.SUBSTR(L_CLOB, 100, 1));
14 FETCH C INTO L_ID;
15 DBMS_OUTPUT.PUT_LINE( 'ID = ' || L_ID );
16 CLOSE C;
17 END;
18 /
PL/SQL procedure successfully completed.
SQL> SELECT * FROM T;
ID TXT
---------- ----------------------------
2 GOOBBYE
-- 커서 C 읽기 일관성 이미지 UNDO SEGMENT 사용
-- LOB의 읽기 일관성 이미지는 LOBSEGMENT 사용
-- RETENTION은 UNDO_RETENTION 설정에 따라 데이터베이스가 변경된 LOG 세그먼트 데이터를 LOG 세그먼트에 보유
-- LOB 세그먼트의 재사용 가능한 빈 공간이 계속적인 INSERT , UPDATE에 의해 즉시 재사용도는 것이 아니다("왜 LOB세그먼트는 자꾸 증가하는가?")
-- 보유기간이 만료되지 않았기 때문에 정보를 재적하면서 대량 삭제로 인해 LOB세그먼가 커지는 경향이 존재
-- RETENTION 옵션대신 LOG STORAGE절에 PCTVERSION을 사용
-- 다른세션이 LOB을 수정하는 동안 LOB을 자주 읽기에는 10% 기본값은 너무 작을 수 있다.
-- 그렇다면 언두 테이블스페이스를 늘리거나, 언두 RETENTION을 늘리거나, RBS 공간을 추가
CACHE절
- NOCACHE 대신 CACHE나 CACHE READS를 선택가능
- 기본값은 NOCACHE
- CACHE READ는 LOB데이터를 디스크에서 버퍼에 캐시하지만, 쓰기는 캐시하지않고 디스크에 직접씀
- CACHE는 읽기와 쓰기 모두 LOB 데이터를 캐시
문법
- ALTER TABLE TABNAME MODIFY LOB(LOBNAME) (CACHE);
- ALTER TABLE TABNAME MODIFY LOB(LOBNAME) (NOCACHE);
LOB STORAGE절
- LOBSEGMENT 와 LOBINDEX 에 동일 하게 적용
BFILE
-- BFILE은 운영체제에서 파일의 포인터다
-- 읽기모드로 접근할 수 있다.
-- BFILE데이터는 읽기 일관성을 제공하지 않는다.
SQL> DROP TABLE T;
Table dropped.
SQL>
SQL> CREATE TABLE T
2 (
3 ID INT PRIMARY KEY,
4 OS_FILE BFILE
5 );
Table created.
SQL>
SQL> CREATE OR REPLACE DIRECTORY MY_DIR AS '/TMP';
Directory created.
SQL> INSERT INTO T VALUES(1, BFILENAME('MY_DIR', 'test.dbf'));
1 row created.
SQL>
SQL> SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T;
SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T
*
ERROR at line 1:
ORA-22288: file or LOB operation GETLENGTH failed
?????????? ??? ?? ???????
ORA-06512: at "SYS.DBMS_LOB", line 787
SQL> COMMIT;
Commit complete.
SQL> UPDATE T
2 SET OS_FILE = BFILENAME('my_dir','test.dbf');
1 row updated.
SQL> SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T;
SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T
*
ERROR at line 1:
ORA-22285: non-existent directory or file for
GETLENGTH operation
ORA-06512: at "SYS.DBMS_LOB", line 787
SQL> CREATE OR REPLACE DIRECTORY "my_dir" AS '/tmp';
Directory created.
SQL> SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T;
SELECT DBMS_LOB.GETLENGTH(OS_FILE) FROM T
*
ERROR at line 1:
ORA-22288: file or LOB operation GETLENGTH failed
?????????? ??? ?? ???????
ORA-06512: at "SYS.DBMS_LOB", line 787