LOB類型的學習、總結


LOB相關的概念

LOB類型:

將信息文件(十進制、二進制)、圖像甚至音頻信息采用數據庫作為保存載體時,就需要使用lob類型數據。

有兩種Lob,Internal Lob和External Lob。Internal Lob是指Lob數據存儲在Oracle數據文件里,External Lob是指Lob數據存儲在數據庫外部的操作系統中。

CLOB:        存儲大量、單字節、字符數據,存儲在內部表空間,用於存儲字符串類型的Lob,如文本和XML文件等,字符串已數據庫字符集編碼。

NLOB:        存儲定寬、多字節、字符數據,多字節國家字符數據,存儲在內部表空間。

BLOB:        存儲較大無結構的二進制數據,存儲在內部表空間。

BFILE:        將二進制文件存儲在數據庫外部的操作系統文件中。存放文件路徑。數據庫存儲一個執行外部文件的指針,所以它是只讀的。

Internal Lob和External Lob的區別

Internal Lob包含CLOB、NLOB和BLOB;External Lob只有BFILE。

Internal LOB可以作為表的一個列保存在表中,external LOB保存在操作系統上的文件中。

Internal LOB將數據以字節流的形式存儲在數據庫的內部。Internal LOB的許多操作都可以參與事務,可以像處理普通數據一樣對其進行備份和恢復操作。

External Lob,即BFILE類型。在數據庫內,該類型僅存儲數據在操作系統中的位置信息,而數據的實體以外部文件的形式存在於操作系統的文件系統中。因而,該類型所表示的數據是只讀的,不參與事務。

Internal LOBs use copy semantics. That is when you INSERT or UPDATE a LOB with a LOB from another row in a table, the LOB locator as well as the LOB value are copied to the row. External LOBs on the other hand use reference semantics. That is only the BFILE location is copied and not the actual operating system file.

   

Each internal LOB column has a distinct LOB locator for each row and a distinct copy of the LOB value. Each BFILE column has its own BFILE locator for each row. However you could have two rows in the table that contain BFILE locators pointing to the same operating system file.

   

對於一般的數據表而言,一個數據表只會對應一個存儲數據段data segment對象。對於分區表,通常一個分區就對應一個單獨的存儲對象。

當數據表中包括lob類型的數據列時,也會有獨特的段對象建立。常規的數據段T之外,另外增加了兩個明顯是系統命名的段對象,類型分別為lobsegment和lobindex。

對Oracle lob類型數據表而言,一個帶lob列的數據表創建是要對應多個數據段創建的。除了傳統的數據表創建的數據段Table Data Segment之外,一個lob列都會生成兩個專門的段:lob段和lob索引段。

   

Lob段(LobSegment)對應的是存放在數據表lob列上的數據。在Oracle的lob類型數據列,有兩種保存位置結構。一個是in-row storage,也就是每一行的lob數據同其他列的數據以行的形式一起保存在數據塊中。這種情況的lob列取值較小。而另一種為out-of-row storage,當lob對象較大,不能保存在一個數據塊中時,可以將其放置在一個獨立lobsegment中進行保存。而out-of-row storage時數據行中lob列上保存的只是一個指向lobsegment對應位置的指針引用。

   

Lob索引段(LobIndex)是Oracle為每一個lob類型列強制生成的索引,主要作用是用於進行lob類型數據檢索加速的操作。Lobindex與lob列共生,如果強制進行刪除操作,是會報錯的。

SQL> drop index SYS_IL0000056069C00002$$;

drop index SYS_IL0000056069C00002$$

ORA-22864: 無法 ALTER 或 DROP LOB 索引

   

在實際物理設計部署過程中,經常有將大對象分區和存儲單獨部署表空間的情況。可以根據實際的情況,將一些很大的lob列連同索引保存在單獨的表空間上。

但是注意,一般數據表而言,lob段和lobindex段是在一個表空間上。即使在SQL語法上存在支持,但是將lob段和lobindex分開存儲的語句通常被忽略掉。

   

   

Lob與其它類型的轉換

通過TO_CLOB可以將CHAR,NCHAR,VARCHAR2,NVARCHAR2,        NCLOB類型轉換成CLOB;

通過TO_LOB可以將LONG RAW轉換成BLOB,        LONG轉換成CLOB;

通過TO_NCLOB可以將CHAR,NCHAR,VARCHAR2,NVARCHAR2,        CLOB轉換成NCLOB。

   

   

LOB段屬性

默認情況下,當定義了含有LOB字段的table后, oracle會自動為每個LOB創建兩個段,lob segment和lob index segment. lob segment存儲了每個lob的具體的值,而lob index segment則存儲了每個lob值的地址.lob segment、lob index segment和table segment存儲在同一個表空間中.oracle為lob段提供了單獨的段屬性.我們在創建table時可以定義將lob和table分別存儲在不同的表空間中。平常定義lob時,我們必須考慮以下幾個比較重要的屬性:

   

chunk:比oracle block size更大的一種邏輯塊,專用於LOB數據的存儲,默認為db_block_size的大小,如果手動定義必須定義為db_block_size的倍數.最大不能超過32K。不合理的chunk定義不及浪費存儲空間,而且還會影響性能.那么在定義前必須了解應用, 每個LOB列的數據的平均大小,盡量減少LOB的空間浪費.看下面的表格能說明一切:

   

Data Size CHUNK Size Disk Space Used to Store the LOB Space Utilization(Percent)

3500 enable storage in row irrelevant 3500 in row 100

3500 disable storage in row 32 KB 32 KB 10

3500 disable storage in row 4 KB 4 KB 90

33 KB 32 KB 64 KB 51

2 GB +10 32 KB 2 GB + 32 KB 99+

上面表格用一些數據說明了chunk跟數據之間的存儲關系,更形象的說明了磁盤空間的利率問題。 紅色標記的部分說明了不合理的chunk定義.必須注意到的LOB中比chunk浪費的空間是不可以重用的.

   

disable/enable storage in row: 默認情況下為enable storage in row, 在沒有分離lob段的情況下,table中的每行數據都存儲在同一個block中,這樣如果lob列很大時,可能會造成嚴重的行鏈接;當lob段和table段分離的情況下,oracle會自動將小於4k的lob數據存儲在table segment,將大於4k的lob數據存儲在lob段.如果設置為 disable storage in row的情況時,在lob段和table段分離的情況下, 不管lob數據多大,oracle都會將lob數據存儲在lob段,這樣就出現了上面的

3500 disable storage in row 32 KB ,32 KB ,10情況,浪費了90%的存儲空間.

   

pctversion n /retention:這兩個屬性用來解決lob段的一致性讀問題。lob的特殊性決定它不能使用undo/rollback segment來管理自己的更新的old version,通常lob會在自己所在的表空間中划分一部分空間來管理自己的undo,保證read consistent.lob中更新原理是在lob segment中分配新的chunk插入新的數據,保留舊的鏡像,如果一個數據有多個更新存在的話, 那么就會存在多個版本.pctversion用來定義lob segment中undo區域的大小,pctverision 是一個百分比,定義所有lob空間用來存放前鏡像的百分比,如果前鏡像使用空間超過這個百分比了,oracle不自動擴展這部分的大小, 會重用這些前鏡像的空間.如果一個lob segment段的更新很頻繁的情況下,那么該lob段的增長可能會很快.retention是9i的新參數, 只能用在tablespace采用ASSM的情況,在lob更新的時候,前鏡像會保留一段時間, 具體的時間由undo_retention參數決定.決定采用乃種undo 方式,必須對應用測試后在決定.

   

nocache/cache reads/cache:定義LOB的cache 方式,nocache為不cache任何 lob數據;cache reads為在lob read的情況下cache數據;cache為讀寫都cache數據.

   

freepools integer:給log segment指定free list.RAC環境下integer為實例的個數.單實例環境下為1

   

index lobindexname (tablespace tablesapce_name ((storage.....):給lob列指定索引存儲參數

   

   

lob創建的例子:

create table person_new(id number(5),name varchar2(30),remark clob,photo blob not null)

lob (remark) store as person_remark(

tablespace person_lob

enable storage in row

chunk 8192

pctversion 2

cache reads

index person_remark_idx)

lob (photo) store as person_photo(

tablespace person_lob

disable storage in row

chunk 16384

pctversion 2

cache reads

index person_photo_idx)

tablespace users

pctfree 10

/

   

   

   

創建實驗環境

create tablespace test datafile '+DATA' size 20m;

create tablespace test_ind datafile '+DATA' size 20m;

create temporary tablespace test_tmp TEMPFILE '+DATA' size 20m;

create tablespace test_blob datafile '+DATA' size 20m;

create user test identified by test default tablespace test temporary tablespace test_tmp;

grant connect,resource to test;

create directory EXPDP as '/backup/expdp';

grant read,write on directory EXPDP to system;

   

alter tablespace test_ind add datafile '+DATA' size 400M;

alter tablespace test_blob add datafile '+DATA' size 400M;

alter tablespace test add datafile '+DATA' size 400M;

   

   

conn test/test

   

create table T1(

id number(8),

name varchar2(10),

addr blob,

res clob,

photo bfile

)

lob (addr) store as testblob

( tablespace test_blob

chunk 16k

disable storage in row

)

lob (res) store as testclob

( tablespace test_blob

chunk 16k

disable storage in row

)

;

   

   

SQL>select table_name,tablespace_name from user_tables;

   

TABLE_NAME                 TABLESPACE_NAME

------------------------------ ------------------------------

T1                         TEST

表是創建在TEST表空間中。

   

Insert Into T1 Values(1,'Gene',empty_blob(),empty_clob(),bfilename('EXPDP','IMG_0210.JPG'));

Insert Into T1 Values(2,'Gene',empty_blob(),'大字段CLOB',bfilename('EXPDP','IMG_0210.JPG'));

Insert Into T1 Values(3,'Gene',empty_blob(),empty_clob(),null);

   

   

SQL> select table_name,column_name,segment_name,tablespace_name,index_name,chunk from user_lobs;

TABLE_NAME COLUMN_NAM SEGMENT_NAME         TABLESPACE_NAME                                         INDEX_NAME                                                         CHUNK

---------- ---------- ------------ ------------------------------ ------------------------------                 ----------

T1                         ADDR         TESTBLOB         TEST_BLOB                                         SYS_IL0000087540C00003$$                         16384

T1                         RES                 TESTCLOB         TEST_BLOB                                         SYS_IL0000087540C00004$$                         16384

可以看到 TESTBLOB、TESTCLOB 這兩個SEGMENT名稱是在創建表的時候定義的

   

select OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME from dba_segments where OWNER='TEST';

SQL> select OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME from dba_segments where OWNER='TEST';

   

OWNER                         SEGMENT_NAME                                                                         SEGMENT_TYPE         TABLESPACE_NAME

------------------------------ --------------------------------------------------------------------------------- ------------------ ------------------------------

TEST                         T1                                                                                 TABLE                 TEST

TEST                         TESTCLOB                                                                          LOBSEGMENT         TEST_BLOB

TEST                         TESTBLOB                                                                          LOBSEGMENT         TEST_BLOB

TEST                         SYS_IL0000087540C00004$$                                                          LOBINDEX         TEST_BLOB

TEST                         SYS_IL0000087540C00003$$                                                          LOBINDEX         TEST_BLOB

   

從這里可以看到 TESTCLOB、TESTBLOB是LOBSEGMENT類型的segment

SYS_IL0000087540C00004$$和SYS_IL0000087540C00003$$ 是LOBINDEX類型的 segment對象.是自動創建的。

   

   

   

   

   

Lob大對象操作、管理

--創建有大對象字段的一張表

export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

grant read,write on directory EXPDP to test;

conn test/test

create table test001

(

fname varchar2(50),

content blob

);

   

create table test002

(

fname varchar2(50),

content clob

);

   

--(一)..准備插入大對象

--1. 創建文件存放目錄(讓Oracle管理,該目錄)

create directory EXPDP as '/backup/expdp';

grant read,write on directory EXPDP to test;

   

--2.可以將該目錄授權給其他用戶訪問

grant read,write on directory EXPDP to scott;

   

--(二).准備將大對象,存放在test001表中

declare

tempimg blob;

tempdir bfile := bfilename('EXPDP','IMG_0210.jpg');

begin

insert into test001 values ('IMG_0210.jpg',empty_blob()) returning content into tempimg;

dbms_lob.fileopen(tempdir);

dbms_lob.loadfromfile(tempimg,tempdir,dbms_lob.getlength(tempdir));

dbms_lob.fileclose(tempdir);

dbms_output.put_line('恭喜你,終於成功了!!!');

commit;

end ;

/

PL/SQL procedure successfully completed.

   

--將Blob對象,寫成磁盤文件

declare

l_file utl_file.file_type;

l_buffer raw(32767);

l_amount binary_integer := 3276;

l_pos int :=1;

l_blob blob;

l_blob_len int;

begin

select content into l_blob from test001;

l_blob_len := dbms_lob.getlength(l_blob);

l_file := utl_file.fopen('EXPDP','HHAHAHAHAHAHAHAHAAHA.JPG','wb');

while l_pos<l_blob_len loop

dbms_lob.read(l_blob,l_amount,l_pos,l_buffer);

utl_file.put_raw(l_file,l_buffer,true);

l_pos := l_pos + l_amount;

end loop;

utl_file.fclose(l_file);

dbms_output.put_line('恭喜你,終於成功了!!!');

end;

/

PL/SQL procedure successfully completed.

實際測試的時候 HHAHAHAHAHAHAHAHAAHA.JPG的大小 跟 IMG_0210.jpg一致,可以打開。

   

/*

文本大對象的寫入和讀取(clob)。

*/

--寫入文本文件第一種方式

declare

tempimg clob;

tempdir bfile := bfilename('EXPDP','70093.txt');

amount int:=dbms_lob.getlength(tempdir);

src_offset int:=1;

dest_offset int:=1;

csid int:=0;

lc int:=0;

warning int;

begin

insert into test002 values ('FIRST',empty_clob()) returning content into tempimg;

dbms_lob.fileopen(tempdir);

dbms_lob.loadclobfromfile(tempimg,tempdir,amount,dest_offset,src_offset,csid,lc,warning);

dbms_lob.fileclose(tempdir);

dbms_output.put_line('恭喜你終於成功了');

commit;

end ;

/

PL/SQL procedure successfully completed.

   

--寫入文本文件第二種方式(通過異常判斷文件結束的)

declare

filecontent clob;

input_file utl_file.file_type;

buffer varchar2(2000);

l_pos int := 1;

amount int;

begin

insert into test002 values ('SECOND',empty_clob()) returning content into filecontent;

input_file := utl_file.fopen('EXPDP','2.txt','r');

   

loop

utl_file.get_line(input_file,buffer);

amount:=length(buffer);

exit when amount<=0;

dbms_lob.write(filecontent,amount,l_pos,buffer);

l_pos:=l_pos+amount;

end loop;

utl_file.fclose(input_file);

dbms_output.put_line('文件寫入完畢');

exception

when no_data_found then

dbms_output.put_line('恭喜你終於成功了');

utl_file.fclose(input_file);

end;

/

PL/SQL procedure successfully completed.

   

--讀取表中的數據,到文件

declare

src clob;

outfile utl_file.file_type;

length integer;

buffer varchar2(8000);

begin

select content into src from test002 where fname='SECOND';

length := dbms_lob.getlength(src);

dbms_lob.read(src,length,1,buffer);

outfile := utl_file.fopen('EXPDP','hahahahhahahahah.txt','w',8000);

utl_file.put(outfile,buffer);

utl_file.fclose(outfile);

dbms_output.put_line('寫入完畢');

end;

/

PL/SQL procedure successfully completed.

   

   

   

   

清理CLOB字段及壓縮CLOB空間

1、創建LOB字段存放表空間:

create tablespace lob_test datafile '/oracle/data/lob_test.dbf' size 500m autoextend on next 10m maxsize unlimited

2、移動LOB字段到單獨存放表空間:

ALTER TABLE CENTER_ADMIN.NWS_NEWS

MOVE LOB(ABSTRACT)

STORE AS (TABLESPACE lob_test);

ABSTRACT---為一CLOB類型的字段

lob_test---為新創建的表空間。

3、清空指定時間段CLOB字段的內容:

update CENTER_ADMIN.NWS_NEWS

set ABSTRACT=EMPTY_CLOB()

where substr(to_char(pubdate,'yyyy-mm-dd'),1,4)='2011'

4、單獨shrink CLOB字段:

ALTER TABLE CENTER_ADMIN.NWS_NEWS MODIFY LOB (ABSTRACT) (SHRINK SPACE);

--注:此方法會在表空間級釋放出部分空間給其他對象使用,但這部分空間在操作系統級還是被占用

5、在操作系統級釋放空間 (這一步 一般不做):

alter database datafile '/oracle/data/lob_test.dbf' resize 400m

---注:絕大多數情況下,不可能一個表空間中只存放一個CLOB字段,若需要從操作系統級真正釋放空間,尚需要shink table或EXP/IMP等操作。

   

   

   

帶LOB字段表的移動

對含blob字段表遷移:

select 'alter table '||t.table_name ||' move tablespace tabespace_name lob('||t.COLUMN_NAME||') store as (tablespace tablespace_name);' from user_lobs t;

   

alter table T1 move tablespace test lob(ADDR) store as (tablespace test_ind);

alter table T1 move tablespace test lob(RES) store as (tablespace test_ind);

   

SQL> alter table T1 move tablespace test lob(ADDR) store as (tablespace test_ind);

   

Table altered.

   

SQL> alter table T1 move tablespace test lob(RES) store as (tablespace test_ind);

   

Table altered.

   

SQL> select OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME from dba_segments where OWNER='TEST';

   

OWNER                         SEGMENT_NAME                                                                         SEGMENT_TYPE         TABLESPACE_NAME

------------------------------ --------------------------------------------------------------------------------- ------------------ ------------------------------

TEST                         T1                                                                                 TABLE                 TEST

TEST                         TESTCLOB                                                                          LOBSEGMENT         TEST_IND

TEST                         TESTBLOB                                                                          LOBSEGMENT         TEST_IND

TEST                         SYS_IL0000087540C00003$$                                                          LOBINDEX         TEST_IND

TEST                         SYS_IL0000087540C00004$$                                                          LOBINDEX         TEST_IND

   

可以看到同一個lob字段的 LOBSEGMENT和LOBINDEX類型的segment同時移動到了TEST_IND表空間。

   

帶LOB字端表的導入導出

create directory EXPDP as '/backup/expdp';

grant read,write on directory EXPDP to system;

export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

expdp system/oracle directory=EXPDP tables=test.t1 dumpfile=20160114expt1.dmp logfile=20160114expt1.log

   

[oracle@primary ~]$ expdp system/oracle directory=EXPDP tables=test.t1 dumpfile=20160114expt1.dmp logfile=20160114expt1.log

   

Export: Release 11.2.0.4.0 - Production on Thu Jan 14 16:36:10 2016

   

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

   

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, Automatic Storage Management, OLAP, Data Mining

and Real Application Testing options

Starting "SYSTEM"."SYS_EXPORT_TABLE_01": system/******** directory=EXPDP tables=test.t1 dumpfile=20160114expt1.dmp logfile=20160114expt1.log

Estimate in progress using BLOCKS method...

Processing object type TABLE_EXPORT/TABLE/TABLE_DATA

Total estimation using BLOCKS method: 192 KB

Processing object type TABLE_EXPORT/TABLE/TABLE

. . exported "TEST"."T1" 6.765 KB 3 rows

Master table "SYSTEM"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded

******************************************************************************

Dump file set for SYSTEM.SYS_EXPORT_TABLE_01 is:

/backup/expdp/20160114expt1.dmp

Job "SYSTEM"."SYS_EXPORT_TABLE_01" successfully completed at Thu Jan 14 16:36:45 2016 elapsed 0 00:00:30

   

   

   

導入

導入表test到scott用戶下,user表空間中,lob字段保存到test_blob中。

   

alter user scott identified by tiger account unlock;

export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK

impdp system/oracle directory=EXPDP tables=test.t1 remap_schema=test:scott remap_tablespace=test:users,TEST_IND:TEST_BLOB dumpfile=20160114expt1.dmp logfile=imp20160114expt1.log

[oracle@primary ~]$ impdp system/oracle directory=EXPDP tables=test.t1 remap_schema=test:scott remap_tablespace=test:users,TEST_IND:TEST_BLOB dumpfile=20160114expt1.dmp logfile=imp20160114expt1.log

   

Import: Release 11.2.0.4.0 - Production on Thu Jan 14 16:53:21 2016

   

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

   

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, Automatic Storage Management, OLAP, Data Mining

and Real Application Testing options

Master table "SYSTEM"."SYS_IMPORT_TABLE_01" successfully loaded/unloaded

Starting "SYSTEM"."SYS_IMPORT_TABLE_01": system/******** directory=EXPDP tables=test.t1 remap_schema=test:scott remap_tablespace=test:users,TEST_IND:TEST_BLOB dumpfile=20160114expt1.dmp logfile=imp20160114expt1.log

Processing object type TABLE_EXPORT/TABLE/TABLE

Processing object type TABLE_EXPORT/TABLE/TABLE_DATA

. . imported "SCOTT"."T1" 6.765 KB 3 rows

Job "SYSTEM"."SYS_IMPORT_TABLE_01" successfully completed at Thu Jan 14 16:53:28 2016 elapsed 0 00:00:05

   

select OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME from dba_segments where OWNER='SCOTT';

SQL> select OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME from dba_segments where OWNER='SCOTT';

   

OWNER                         SEGMENT_NAME                                                                         SEGMENT_TYPE         TABLESPACE_NAME

------------------------------ --------------------------------------------------------------------------------- ------------------ ------------------------------

SCOTT                         PK_EMP                                                                                 INDEX                 USERS

SCOTT                         PK_DEPT                                                                                 INDEX                 USERS

SCOTT                         T1                                                                                 TABLE                 USERS

SCOTT                         SALGRADE                                                                          TABLE                 USERS

SCOTT                         EMP                                                                                 TABLE                 USERS

SCOTT                         DEPT                                                                                 TABLE                 USERS

SCOTT                         TESTCLOB                                                                          LOBSEGMENT         TEST_BLOB

SCOTT                         TESTBLOB                                                                          LOBSEGMENT         TEST_BLOB

SCOTT                         SYS_IL0000087707C00004$$                                                          LOBINDEX         TEST_BLOB

SCOTT                         SYS_IL0000087707C00003$$                                                          LOBINDEX         TEST_BLOB

   

10 rows selected.

數據已經導入到 user用戶下,原來lob的字段導入到test_blob表空間中

   

   

LOB性能問題

lob字段默認生成lobindex和lobsegment。        在不指定特定表空間情況下,lob字段索引存儲到系統表空間下。

當lob存放在表中的時候,        它可以被緩存,對於它的操作效率遠遠高於存儲在lobsegment中的lob(不用lobindex)。

當lob存放logsegment中,        缺省不在緩沖區緩存,對於lob的讀寫都是物理IO,代價非常高,所以對於大於4kb的lob字段千萬不要頻繁更新,效率非常低。

當lob存放logsegment中,        可定義指定使用cache(默認是nocache),這對於中等大小的lob(比如幾k~幾十k)很有效果,減少物理IO。

綜上看來,盡量不用blob字段,假設用的話要分配好表空間和配置合適參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM