oracle数值类型--LOB+ROWID/UROWID
2019獨角獸企業重金招聘Python工程師標準>>>
Oracle中支持4種類型的LOB:
CLOB:字符LOB。存儲大量的文本信息,如XML或者只是純文本。這個數據類型需要進行字符集轉換,也就是說,在獲取時,這個字段中的字符會從數據庫的字符集轉換為客戶的字符集,而在修改時會從客戶的字符集轉換為數據庫的字符集。
NCLOB:這是另一種類型的字符LOB。存儲在這一列中的數據所采用的字符集是數據庫的國家字符集,而不是數據庫的默認字符集。
BLOB:二進制LOB。存儲大量的二進制信息,如字處理文檔,圖像換。應用向BLOB中寫入什么位和字節,BLOB就會返回什么為和字節。
BFILE:二進制文件LOB。帶BFILE列的數據庫中存儲的只是操作系統中某個文件的一個指針。這個文件在數據庫之外維護,根本不是數據庫的一部分。BFILE提供了文件內容的只讀訪問。
1 內部LOB
scott@ORCL>create table t2 ( id int primary key,3 txt clob4 )5 /表已創建。scott@ORCL>select dbms_metadata.get_ddl( 'TABLE', 'T' )2 from dual;DBMS_METADATA.GET_DDL('TABLE','T') --------------------------------------------------------------------------------CREATE TABLE "SCOTT"."T"( "ID" NUMBER(*,0),"TXT" CLOB,PRIMARY KEY ("ID")USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 NOCOMPRESS LOGGINGTABLESPACE "TOOLS" ENABLE) SEGMENT CREATION DEFERREDPCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGINGTABLESPACE "TOOLS"LOB ("TXT") STORE AS BASICFILE (TABLESPACE "TOOLS" ENABLE STORAGE IN ROW CHUNK 8192 RETENTIONNOCACHE LOGGING )LOB顯然有以下屬性:
一個表空間(這個例子中即為TOOLS)
ENABLE STORAGE IN ROW作為一個默認屬性
CHUNK 8192
RETENTION
NOCACHE
LOB列總是會帶來一種多段對象(multisegment object),這個表會使用多個物理段。
實際LOB數據存儲在lobsegment中,lobindex用于執行LOB的導航,來找出其中的某些部分。創建一個LOB列時,一般來說,存儲在行中的這是一個指針(pointer),或LOB定位器(LOB locator)。應用所獲取的就是這個LOB定位器。當請求得到LOB的“1,2000~2,000字節”時,將對lobindex使用LOB定位器來找出這些字節存儲在哪里,然后再訪問lobsegment。可以用lobindex很容易地找到LOB的各個部分。可以把LOB想成是一種主/明細關系。LOB按“塊”(chunk)或(piece)來存儲,每個片段都可以訪問。例如,如果我們使用表來實現一個LOB,可以如下做到這一點:
Create table parent ( id int primary key, other-data... ); Create table lob ( id references parent on delete cascade, chunk_number int, data <datatype>(n), primary key (id,chunk_number) );從概念上講,LOB的存儲與之非常相似,創建這兩個表時,在LOB表的ID.CHUNK_NUMBER上要有一個主鍵(這對應于Oracle創建的lobindex),而且要有一個LOB表來存儲數據塊(對應于lobsegment)。LOB列為我們透明地實現了這種主/明細結構。
1. LOB表空間
從DBMS_METADATA返回的CREATE TABLE語句包括以下內容:
LOB ("TXT") STORE AS BASICFILE (TABLESPACE "TOOLS"....TABLESPACE 存儲lobsegment和lobindex表空間,這可能與表本身所在的表空間不同。也就是說,保存LOB數據的表空間可能不同于保存實際表數據的表空間。從管理的角度看,LOB數據類型表示一種規模很大的信息。如果表有數百萬行,而每行有一個很大的LOB,那么LOB就會極為龐大。為LOB數據單獨使用一個表空間有利于備份和恢復以及空間管理,將表與LOB數據分離就很有意義。例如,LOB數據使用另外一個統一的區段大小,而不是普通表數據所用的區段大小。另一個原因則出于I/O性能的考慮。默認情況下,LOB不在緩沖區緩存中進行緩存。因此,默認情況下,對于每個LOB訪問,不論是讀還是寫,都會帶來一個物理I/O(從磁盤直接讀,或者向磁盤直接寫)。
LOB可能是內聯的(inline),或者存儲在表中。在這種情況下,LOB數據會被緩存,但是這只適用于小于4,000字節的LOB。
lobindex和lobsegment總是會在同一個表空間中。實際上,lobindex的所有存儲特征都是從lobsegment繼承的。
2. IN ROW子句
前面的DBMS_METADATA返回的CREATE TABLE語句還包括以下內容:
LOB ("TXT") STORE AS BASICFILE (...ENABLE STORAGE IN ROW ...這控制了LOB數據是否總與表分開存儲(存儲在lobsegment中),或是有時可以與表一同存儲,而不用單獨放在lobsegment中。如果設置了ENABLE STORAGE IN ROW,而不是DISABLE STORAGE IN ROW,小LOB(最多4,000字節)就會像VARCHAR2一樣存儲在表本身中。只有當LOB超過了4,000字節時,才會“移出”到lobsegment中。
默認行為是啟用行內存儲(ENABLE STORAGE IN ROW),而且一般來講,如果知道LOB總是能在表本身中放下,就應該采用這種默認行為,這樣既能避免單獨存儲的開銷,又能避免獲取LOB時所需的物理I/O。
我們將創建包括有兩個LOB的表,其中一個LOB可以在行內存儲數據,而另一個LOB禁用了行內存儲:
scott@ORCL>create table t2 ( id int primary key,3 in_row clob,4 out_row clob5 )6 lob (in_row) store as ( enable storage in row )7 lob (out_row) store as ( disable storage in row )8 /表已創建。在這個表中,我們將插入一些串數據,所有這些串的長度都不超過4,000字節:
scott@ORCL>insert into t2 select rownum,3 owner || ' ' || object_name || ' ' || object_type || ' ' || status,4 owner || ' ' || object_name || ' ' || object_type || ' ' || status5 from all_objects6 /已創建72081行。scott@ORCL>commit;提交完成。現在,想讀取每一行,在此使用了DBMS_MONITOR包,并啟用了SQL_TRACE(具體參見?tkprof 性能分析?),執行這個工作時,可以看到這兩個表獲取數據時的性能:
SELECT IN_ROW FROMT WHERE ID = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 72081 1.09 1.28 0 0 0 0 Fetch 72081 1.18 1.11 0 216243 0 72081 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 144163 2.27 2.40 0 216243 0 72081Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 84 (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=2015 card=1)1 INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 85254)******************************************************************************** SELECT OUT_ROW FROMT WHERE ID = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 72081 1.13 0.88 0 0 0 0 Fetch 72081 7.47 26.76 72081 504567 0 72081 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 144163 8.61 27.65 72081 504567 0 72081Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 84 (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_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 85254)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.00direct path read 72008 0.18 18.79獲取IN_ROW列顯著地快得多,而且所占用的資源也遠遠少于OUT_ROW列。可以看到,它使用了216,243次邏輯I/O(查詢模式獲取),而OUT_ROW列使用的邏輯I/O次數是它的兩倍。這些額外的邏輯I/O 是對lobindex段的I/O(為了找到LOB的各個部分)。
另外,可以看到,對于OUT_ROW列,獲取72081行會帶來72081次物理I/O,而這會導致同樣數目的“直接路徑讀”I/O等待。這些都是對非緩存LOB數據的讀取。在這種情況下,通過啟用LOB數據的緩存,可以緩解這個問題,但是這樣一來,我們又必須確保為此要有足夠多的額外的緩沖區緩存。另外,如果確實有非常大的LOB,我們可能并不希望緩存這些數據。
這種行內/行外存儲設置不僅會影響讀,還會影響修改。如果我們要用小串更新前100行,并用小串插入100個新行,再使用同樣的技術查看性能,會觀察到:
scott@ORCL>alter system set timed_statistics=true scope=both;系統已更改。scott@ORCL>alter session set sql_trace = true;會話已更改。scott@ORCL>create sequence s start with 100000;序列已創建。scott@ORCL>declare2 l_cnt number;3 l_data varchar2(32765);4 begin5 dbms_monitor.session_trace_enable;6 for i in 1 .. 1007 loop8 update t set in_row =9 to_char(sysdate,'dd-mon-yyyy hh24:mi:ss') where id = i;10 update t set out_row =11 to_char(sysdate,'dd-mon-yyyy hh24:mi:ss') where id = i;12 insert into t (id, in_row) values ( s.nextval, 'Hello World' );13 insert into t (id,out_row) values ( s.nextval, 'Hello World' );14 end loop;15 end;16 /PL/SQL 過程已成功完成。scott@ORCL>show parameter user_dump_dest;NAME TYPE VALUE ------------------------ ------ ------------------------------------ user_dump_dest\diag\rdbm string d:\app\administrators\orcl\orcl\tracescott@ORCL> select username,sid,serial# from v$session where username='SCOTT';USERNAME SID SERIAL# -------- ----- -------- SCOTT 11 108scott@ORCL>select 'orcl_ora_'||spid||'.trc' from v$process where addr = (select paddr from v$session where sid=11);'ORCL_ORA_'||SPID||'.TRC' -------------------------------------------------------------------------- orcl_ora_4000.trcscott@ORCL>alter session set sql_trace = false;會話已更改。scott@ORCL>exit 從 Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options 斷 開C:\Users\Administrator>d:D:\>cd app\Administrator\diag\rdbms\orcl\orcl\traceD:\app\Administrator\diag\rdbms\orcl\orcl\trace>tkprof orcl_ora_4000.trc f:\2018 0906.txtTKPROF: Release 11.2.0.1.0 - Development on 星期四 9月 6 14:32:55 2018Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.D:\app\Administrator\diag\rdbms\orcl\orcl\trace>在得到的TKPROF報告中可以觀察到類似的結果:
UPDATE T SET IN_ROW = TO_CHAR(SYSDATE,'dd-mon-yyyy hh24:mi:ss') WHEREID = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 100 0.01 0.04 0 201 208 100 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 101 0.01 0.04 0 201 208 100Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 84 (recursive depth: 1)Rows Row Source Operation ------- ---------------------------------------------------0 UPDATE T (cr=3 pr=0 pw=0 time=0 us)1 INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=2015 card=1)(object id 85254)Elapsed times include waiting on following events:Event waited on Times Max. Wait Total Waited---------------------------------------- Waited ---------- ------------direct path write 84 0.00 0.02asynch descriptor resize 163 0.00 0.00 ******************************************************************************** UPDATE T SET OUT_ROW = TO_CHAR(SYSDATE,'dd-mon-yyyy hh24:mi:ss') WHEREID = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 100 0.01 0.11 3 1657 2606 100 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 101 0.01 0.11 3 1657 2606 100Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 84 (recursive depth: 1)Rows Row Source Operation ------- ---------------------------------------------------0 UPDATE T (cr=12 pr=1 pw=1 time=0 us)1 INDEX UNIQUE SCAN SYS_C0020634 (cr=2 pr=0 pw=0 time=0 us cost=1 size=253 card=1)(object id 85254)Elapsed times include waiting on following events:Event waited on Times Max. Wait Total Waited---------------------------------------- Waited ---------- ------------Disk file operations I/O 2 0.00 0.00db file sequential read 1 0.02 0.02direct path write 10 0.00 0.00asynch descriptor resize 18 0.00 0.00可以看到,行外LOB的更新占用了更多的資源。它要花一定的時間完成直接路徑寫(物理I/O),并執行更多的當前模式獲取以及查詢模式獲取。這些都源于一點,即除了維護表本身外,還必須維護lobindex和lobsegment。INSERT操作也顯示出了同樣的差異:
INSERT INTO T (ID, IN_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.00 0.01 1 3 324 100 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 101 0.00 0.01 1 3 324 100Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 84 (recursive depth: 1)Rows Row Source Operation ------- ---------------------------------------------------0 LOAD TABLE CONVENTIONAL (cr=2 pr=1 pw=0 time=0 us)1 SEQUENCE S (cr=1 pr=0 pw=0 time=0 us)Elapsed times include waiting on following events:Event waited on Times Max. Wait Total Waited---------------------------------------- Waited ---------- ------------db file sequential read 3 0.01 0.01direct path write 92 0.00 0.02asynch descriptor resize 178 0.00 0.00 ******************************************************************************** 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.03 0.10 1 1188 1947 100 Fetch 0 0.00 0.00 0 0 0 0 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 101 0.03 0.10 1 1188 1947 100Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: 84 (recursive depth: 1)Rows Row Source Operation ------- ---------------------------------------------------0 LOAD TABLE CONVENTIONAL (cr=11 pr=0 pw=1 time=0 us)1 SEQUENCE S (cr=0 pr=0 pw=0 time=0 us)Elapsed times include waiting on following events:Event waited on Times Max. Wait Total Waited---------------------------------------- Waited ---------- ------------direct path write 1 0.00 0.00注意讀和寫使用的I/O都有所增加。總之,由此顯示出,如果使用一個CLOB,而且很多串都能在“行內”放下(也就是說,小于4,000字節),那么使用默認的ENABLE STORAGE IN ROW設置就是一個不錯的想法。
3. CHUNK子句
前面的DBMS_METADATA返回的CREATE TABLE語句包括以下內容:
LOB ("TXT") STORE AS BASICFILE (...CHUNK 8192...LOB存儲在塊(chunk)中;指向LOB數據的索引會指向各個數據塊。塊(chunk)是邏輯上連續的一組數據庫塊(block),這也是LOB的最小分配單元,而通常數據庫的最小分配單元是數據庫塊。CHUNK大小必須是Oracle塊大小的整數倍,只有這樣才是合法值。
從兩個角度看,選擇CHUNK大小時必須當心。首先,每個LOB實例(每個行外存儲的LOB值)會占用至少一個CHUNK。一個CHUNK有一個LOB值使用。如果一個表有100行,而每行有一個包含7KB數據的LOB,你就會分配100個CHUNK,如果將CHUNK大小設置為32KB,就會分配100個32KB的CHUNK。如果將CHUNK大小設置為8KB,則(可能)分配100個8KB的CHUNK。關鍵是,一個CHUNK只能有一個LOB使用(兩個LOB不會使用同一個CHUNK)。如果選擇了一個CHUNK大小,但不符合你期望的LOB大小,最后就會浪費大量的空間。例如,如果表中的LOB平均有7KB,而你使用的CHUNK大小為32KB,對于每個LOB實例你都會“浪費”大約25KB的空間,另一方面,倘若使用8KB的CHUNK,就能使浪費減至最少。
還需要注意要讓每個LOB實例相應的CHUNK數減至最少。有一個lobindex用于指向各個塊,塊越多,索引就越大。如果有一個4MB的LOB,并使用8KB的CHUNK,你就至少需要512個CHUNK來存儲這個消息。這也說明,至少需要512個lobindex條目指向這些CHUNK。另外,這還會影響獲取性能,因為與讀取更少但更大的CHUNK相比,現在要花更長的數據來讀取和管理許多小CHUNK。我們最終的目標是:使用一個能使“浪費”最少,同時又能高效存儲數據的CHUNK大小。
4. PCTVERSION子句
控制LOB的讀一致性。lobsegment并不使用undo來記錄其修改;而是直接在lobsegment本身中維護信息的版本。lobindex會像其他段一樣生成undo,但是lobsegment不會。相反,修改一個LOB時,Oracle會分配一個新的CHUNK,并且仍保留原來的CHUNK。如果回滾了事務,對LOB索引所做的修改會回滾,索引將再次指向原來的CHUNK。因此,undo維護會在LOB段本身中執行。修改數據時,原來的數據庫保持不動,此外會創建新數據。
讀LOB數據時這也很重要。LOB是讀一致的,這與所有其他段一樣。如果你在上午9:00獲取一個LOB定位器,你從中獲取的LOB數據就是“上午9:00那個時刻的數據”。這就像是你在上午9:00打開了一個游標(一個結果集)一樣,所生成的行就是那個時間點的數據行。與結果集類似,即使別人后來修改了LOB數據。在此,Oracle會使用lobsegment,并使用logindex的讀一致視圖來撤銷對LOB的修改,從而提取獲取LOB定位器當時的LOB數據。它不會使用logsegment的undo信息,因為根本不會為logsegment本身生成undo信息。
可以很容易地展示LOB是讀一致的,考慮以下這個小表,其中有一個行外LOB(存儲在logsegment中):
scott@ORCL>create table t2 ( id int primary key,3 txt clob4 )5 lob( txt) store as ( disable storage in row )6 /表已創建。scott@ORCL>insert into t values ( 1, 'hello world' );已創建 1 行。scott@ORCL>commit;提交完成。如果取出LOB定位器,并在這個表上打開一個游標,如下:
scott@ORCL>declare2 l_clob clob;34 cursor c is select id from t;5 l_id number;67 begin8 select txt into l_clob from t; ## 取出LOB定位器9 open c; ## 并在這個表上打開一個游標1011 update t set id = 2, txt = 'Goodbye'; ## 然后修改行,并提交12 commit;13 #通過使用LOB定位器和打開的游標,會提供“獲取LOB定位器或打開游標那個時間點”的數據14 dbms_output.put_line( dbms_lob.substr( l_clob, 100, 1 ) );15 fetch c into l_id;16 dbms_output.put_line( 'id = ' || l_id );17 close c;18 end;19 / hello world id = 1PL/SQL 過程已成功完成。但是數據庫中的數據很可能已經更新/修改:
scott@ORCL>select * from t;ID TXT ---------- --------2 Goodbye游標C的讀一致映像來自undo段,而LOB的讀一致映像則來自LOB段本身。
PCTVERSION控制著用于實現LOB數據版本化的已分配LOB空間的百分比(這些數據庫塊由某個時間點的LOB所用,并處在lobsegment的HWM以下)。對于許多使用情況來說,默認設置12%就足夠了,因為在很多情況下,只是要INSERT和獲取LOB(通常不會執行LOB的更新;LOB往往會插入一次,而獲取多次)。因此,不必為LOB版本化預留太多的空間(甚至可以沒有)。
不過,如果應用確實經常修改LOB,倘若頻繁地讀LOB,與此同時另外某個會話正在修改這些LOB,12%可能就太小了。如果處理LOB時遇到一個ORA-22924錯誤,解決方案不是增加undo表空間的大小,也不是增加undo保留時間(UNDO_RETENTION),如果你在使用手動undo管理,那么增加更多RBS空間也不能解決這個問題。而是應該使用以下命令:
ALTER TABLE tabname MODIFY LOB (lobname) ( PCTVERSION n );并增加lobsegment中為實現數據版本化所用的空間大小。
5. RETENTION子句
前面的DBMS_METADATA返回的CREATE TABLE語句包括以下內容:
LOB ("TXT") STORE AS BASICFILE (... RETENTION ...這個子句與PCTVERSION子句是互斥的,如果數據庫中使用自動undo管理,就可以使用這個子句。RETENTION子句在lobsegment中使用基于時間的機制來保留數據。數據庫會設置參數UNDO_RETENTION,指定要把undo信息保留多長時間來保證一致讀。在這種情況下,這個參數也適用于LOB數據。
不能使用這個子句來指定保留時間;而要從數據庫的UNDO_RETENTION設置來繼承它。
6. CACHE子句
前面的DBMS_METADATA返回的CREATE TABLE語句包括以下內容:
LOB ("TXT") STORE AS BASICFILE (... NOCACHE ...除了NOCACHE,這個選項還可以是CACHE或CACHE READS。這個子句控制了lobsegment數據是否存儲在緩沖區緩存中。默認的NOCACHE指示,每個訪問都是從磁盤的一個直接讀,類似地,每個寫/修改都是對大盤的一個直接寫。CACHE READS允許緩存從磁盤讀的LOB數據,但是LOB數據的寫操作必須直接寫至磁盤。CACHE則允許讀和寫時都能緩存LOB數據。
如果只有小規模或中等規模的LOB(例如,使用LOB來存儲只有幾KB的描述性字段),對其緩存就很有意義。如果不緩存,當用戶更新描述字段時,還必須等待I/O將數據寫指磁盤(將執行一個CHUNK大小的I/O,而且用戶要等待這個I/O完成)。如果你在執行多個LOB的加載,那么加載每一行時都必須等待這個I/O完成。所以啟用執行LOB緩存很合理。可以打開和關閉緩存,來看看會有什么影響:
對于一個規模很多的初始加載,啟用LOB的緩存很有意義,這允許DBWR在后臺將LOB數據寫至磁盤,而客戶應用可以繼續加載更多的數據。對于頻繁訪問或修改的小到中等規模的LOB,緩存就很合理,可以部門讓最終用戶實時等待物理I/O完成。不過,對于一個大小為50MB的LOB,把它放在緩存中就沒有道理了。
此時可以充分使用Keep池或回收池。并非在默認緩存中將lobsegment數據與所有“常規”數據一同緩存,可以使用保持池或回收池將其分開緩存。采用這種方式,既能緩存LOB數據,而且不影響系統中現有數據的緩存。
7. LOB STORAGE子句
它有一個完整的存儲子句,可以用來控制物理存儲特征。這個存儲子句同樣適用于lobsegment和lobindex,對一個段的設置也可以用于另一個段。假設有一個本地管理的表空間,LOB的相關設置將是FREELISTS、FREELIST GROUPS和BUFFER_POOL。FREELISTS和FREELIST GROUPS與表段的關系 同樣適用于lobindex段,因為lobindex與其他索引段的管理是一樣的。如果需要高度并發地修改LOB,可能最好在索引段上設置多個FREELISTS。
對LOB段使用保持池或回收池可能是一個很有用的技術,這樣就能緩存LOB數據,而且不會“破壞”現有的默認緩沖區緩存。并不是將LOB與常規表一同放在塊緩沖區中,可以在SGA中專門為這些LOB對象預留一段專用的內存。BUFFER_POOL子句可以達到這個目的。
2. BFILE
BFILE類型只是操作系統上一個文件的指針。它用于為這些操作系統文件提供只讀訪問。
使用BFILE時,還有使用一個Oracle DIRECTORY對象。DIRECTORY對象只是將一個操作系統目錄映射至數據庫中的一個“串”或一個名稱(以提供可移植性;你可能想使用BFILE中的一個串,而不是操作系統特定的文件名約定)。作為一個小例子,下面創建一個帶BFILE列的表,并創建一個DIRECTORY對象,再插入一行,其中引用了文件系統中的一個文件:
scott@ORCL>create table t2 ( id int primary key,3 os_file bfile4 )5 /表已創建。scott@ORCL>create or replace directory my_dir as '/tmp/'2 /目錄已創建。scott@ORCL>insert into t values ( 1, bfilename( 'MY_DIR', 'test.dbf' ) );已創建 1 行。現在,就可以把BFILE當成一個LOB來處理,因為它就是一個LOB。例如,可以做下面的工作:
scott@ORCL>create or replace directory MY_DIR as 'd:/test';目錄已創建。scott@ORCL>insert into t values ( 1, bfilename( 'MY_DIR', '11.txt'));已創建 1 行。scott@ORCL>select dbms_lob.getlength(os_file) from t;DBMS_LOB.GETLENGTH(OS_FILE) ---------------------------28可以看到所指定的文件大小為28kb。如果使用混合大小寫或小寫,會得到以下錯誤:
scott@ORCL>update t set os_file = bfilename( 'my_dir', '11.txt' );已更新 1 行。scott@ORCL>select dbms_lob.getlength(os_file) from t; select dbms_lob.getlength(os_file) from t* 第 1 行出現錯誤: ORA-22285: 對不存在的目錄或文件進行 GETLENGTH 操作 ORA-06512: 在 "SYS.DBMS_LOB", line 787Oracle中的DIRECTORY對象是標識符,而默認情況下標識符都以大寫形式存儲。BFILENAME內置函數接受一個串,這個串的大小寫必須與數據字典中存儲的DIRECTORY對象的大小寫完全匹配。所以,必須在BFILENAME函數中使用大寫,或者在創建DIRECTORY對象時使用加引號的標識符:
scott@ORCL>create or replace directory "my_dir" as 'd:/test';目錄已創建。scott@ORCL>select dbms_lob.getlength(os_file) from t;DBMS_LOB.GETLENGTH(OS_FILE) ---------------------------28不建議使用加引號的標識符;而傾向于在BFILENAME調用中使用大寫。加引號的標識符屬于“異類”,可能會在以后導致混淆。
BFILE在磁盤上占用的空間不定,這取決于DIRECTORY對象名的文件名的長度。
與其他LOB數據不同,BFILE數據不是“讀一致”的。由于BFILE在數據庫之外管理,對BFILE解除引用時,不論文件上發生了什么,都會反映到得到的結果中。所以,如果反復讀同一個BFILE,可能會產生不同的結果,這與對CLOB、BLOB或NCLOB使用LOB定位器不同。
ROWID/UROWID類型
ROWID是數據庫中一行的地址。ROWID中編入了足夠多的信息,足以在磁盤上找到行,以及標識ROWID所指向的對象(表等)。ROWID有一個“近親”UROWID,它用于表,如IOT和通過異構數據庫網關訪問的沒有固定ROWID表。UROWID是行主鍵值的一個表示,因此,其大小不定,這取決于它指向的對象。
每個表中的每一行都有一個與之關聯的ROWID或UROWID。從表中獲取時,把它們看作為偽列(pseudo column),這說明它們并不真正存儲在行中,而是行的一個推導屬性。ROWID基于行的物理位置生成;它并不隨行存儲。UROWID基于行的主鍵生成,所以從某種意義上講,好像它是隨行存儲的,但是事實上并非如此,因為UROWID并不作為一個單獨的列存在,而只是作為現有列的一個函數。
以前ROWID是不可變的。插入一行時,會為之關聯一個ROWID(一個地址),而且這個ROWID會一直與該行關聯,直到這一行被刪除(被物理地從數據庫刪除)。但是,后來情況發生了變化,因為現在有些操作可能會導致行的ROWID改變,例如:
在分區表中更新一行的分區鍵,使這一行必須從一個分區移至另一個分區。
使用FLASHBACK TABLE命令將一個數據庫表恢復到以前的每個時間點。
執行MOVE操作以及許多分區操作,如分解或合并分區。
使用ALTER TABLE SHRINK SPACE命令執行段收縮。
如今,由于ROWID可能過一段時間會改變(因為它不再是不可變的),所以不建議把它們作為單獨的列物理地存儲在數據庫表中。也就是說,使用ROWID作為一個數據庫列的數據類型被認為是一種不好的實踐做法。應當避免這種做法,而應使用行的主鍵(這應該是不可變的),另外引用完整性可以確保數據的完整性。對此用ROWID類型是做不到的,不能用ROWID創建從子表到一個父表的外鍵,而且不能保證跨表的完整性。你必須使用主鍵約束。
ROWID作為行的一個物理地址,要訪問任何表中的某一行,這是最快的方法。如果應用從數據庫讀出數據并將其提供給最終用戶,它試圖更新這一行時就可以使用ROWID。應用這種方式,只需最少的工作就可以更新當前行(例如,不需要索引查找再次尋找行),并通過驗證行值未被修改來確保這一行與最初讀出的行是同一行。所以,在采用樂觀鎖定的應用中ROWID還是有用的。
轉載于:https://my.oschina.net/u/1862478/blog/1936561
總結
以上是生活随笔為你收集整理的oracle数值类型--LOB+ROWID/UROWID的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过ribbon 根据服务名获取所有服务
- 下一篇: aoj0558