1.LOB對象的分類
Oracle
支持多種類型的大對象,用於存儲非結構化的數據,如圖片、文檔等內容。應用最爲普遍的是LOB
類型,LOB
有4
種類型:
--CLOB
字符大對象,用於替換較老的LONG
類型;
--BLOB
二進制大對象,主要用於存儲二進制格式的大對象
--NCLOB
基於國家語言字符集的字符大對象
--BFILE
大對象存儲於數據庫外部的操做系統文件系統中
在ZLHIS
及ZLBH
中都大量應用了LOB
類型來保存諸如,電子病歷、序列化對象、檢查圖像結果等信息;
文本討論的內容不包括BFILE
類型。
2. LOB
對象的存儲結構
若是表中存儲在lob
對象,將會建立兩個新增的物理段結構:
--LOBINDEX , LOB
索引用於快速定位LOB
段中的LOB
對象
--LOBSEGMENT
,LOB
段
能夠經過DBA_LOBS
、ALL_LOBS
、USER_LOBS
視圖來查看LOB
段的信息,例如:
SQL> select column_name,segment_name,index_name
2 from dba_lobs
3 where table_name='
病歷標記圖形
'
4 and owner='ZLHIS'
5 /
COLUMN_NAME SEGMENT_NAME INDEX_NAME
-------------------- ------------------------------ -------------------
圖形
SYS_LOB0000052398C00004$$ SYS_IL0000052398C00004$$
上述*_LOBS
視圖提供了下列的列:
OWNER
表全部者
TABLE_NAME
表名稱
COLUMN_NAME
LOB
列的名稱
SEGMENT_NAME
LOB
段名稱
INDEX_NAME
LOB Index
的名稱
CHUNK
顆粒大小(
單位爲字節)
PCTVERSION
PctVersion
參數(
後面有詳細介紹)
CACHE
LOB
段是否開啓CACHE (yes/no)
LOGGING
Logging
選項
(yes/no)
IN_ROW
是否開啓在行內存儲選項
(yes/no)
在內部,Oracle
經過一個叫作定位器的指針來定位特定行對應的LOB
對象,在LOB
中有三種不一樣類型的結構:
--Lob locator
,佔用20
個字節,存儲於表段中;
--Lob Inode
,最少16
字節,存儲於LOB Index
段中
--Data array
,真實的二進制數據;
三種結構示意以下:
3. LOB
存儲參數
3.1 表空間
LOB
對象存儲在那一個表空間中,取決於你在Lob
對象中的storage
子句設置:
--
若是沒有爲LOB
指定表空間,則LOB
段與LOBIndex
都存儲到與表相同的表空間上;
--
若是指定了表空間,則LOB
段與LobIndex
都存儲到指定的表空間上;
爲LOB
類型指定存儲表空間的例子以下:
create table ZLHIS.
病歷標記圖形
(
編碼
VARCHAR2(4) not null,
名稱
VARCHAR2(30),
簡碼
VARCHAR2(10),
圖形
BLOB
)
LOB(
圖形
)
STORE AS
病歷標記圖形
_
圖形
_LOB (
TABLESPACE zl9eprlob
pctversion 10 disable storage in row chunk 4k
INDEX
病歷標記圖形
_
圖形
_LOB_INDEX (
TABLESPACE zl9eprlob
) )
也能夠爲
LOB
段與
LOB Index
指定名稱,若是沒有指定則由
Oracle
自動生成一個惟一名稱。
3.2
存儲在行內仍是行外
LOB
是否存儲在行內,經過enalbe storage in row
和disable storage in row
來進行控制,這個選項只能在表建立時指定,
存儲在行內的語法以下:
STORE AS ( enable storage in row )
若是LOB
數據小於4000
字節,ORACLE
將LOB
存儲於與表相同的段內;
實際上,最大的存儲在行內的LOB
大小是3964
字節。若是LOB
數據大於3964
字節將存儲到獨立的LOB
段上(也就是存儲在行外了)。
若是LOB
對象大於3964
字節,且設置了」enable storage in row」
,則LOB
列中在38
到84
字節處存儲LOB
對象的控制數據。同時須要注意的是,行內存儲較大的LOB
對象,可能形成行遷移現象;好比,存儲3900
字節的LOB
對象到2k
的數據塊裏,這一行將存儲在2
個或更多的塊上;若是有大量的lob
存在這種現象,可能極大的影響LOB
的讀寫性能。
一樣,若是存儲在行內,LOB
數據與標準的結構化數據在redo/undo
機制的上是徹底相同的,
關於這個內容後面還會有說明。
存儲在行外的語法以下
STORE AS ( disable storage in row )
這個選項將全部的LOB
數據存儲到獨立的LOB
段上,而不論LOB
對象的大小。20
個字節的定位器(Locator
)指針存儲在表的行裏,惟一標識存儲在LOB
段中的LOB
數據。LOB INDEX
包括了INODE
與LOCATOR
,這樣就有了LOB
段中的數據塊的映射關係,經過存儲在行內的LOCATOR
與LOB INDEX
來快速檢索特定的LOB
數據。
存儲在行外的
LOB
數據最小的段分配單位是數據庫塊(
DB_BLOCK_SIZE
),好比
8K
;這樣即便你的
LOB
對象很小,也將至少佔用一個數據塊;若是你的
chink size
設置爲大於塊的
1
倍大小,好比
10K,
一個
LOB
數據將佔用至少
2
個數據塊。
存儲在行內的
LOB(
注意即便啓用了存儲在行內的特性,要存儲在行內也必須是小於
4000
字節的
LOB
對象
)
,在事務中僅僅產生行中存儲的定位器
(LOCATOR)
與
LOB INDEX
的
UNDO
信息,相比存儲在行外的
LOB
對象就少了許多。存儲在行外的
LOB
數據的存取,則使用直接路徑的方式進行讀取,也就是繞過數據庫緩存來進行讀取。
3.3
顆粒大小(CHUNK )
指定
CHUNK
大小的語法以下:
STORE AS ( CHUNK bytes )
CHUNK
只能在建立時指定。CHUNK
的單位爲字節,只能是DB_BLOCK_SIZE
的倍數;也就是說最小爲數據塊的大小,Oracle
將自動取一個最接近DB_BLOCK_SIZE
倍數的大小。例如, db_block_size
設置爲2k
的狀況下,將chunk
設置爲3000
字節,
則chunk
將自動設置爲4096
字節。經過一個實驗來講明一下:
--
建表時,將
CHUNK
指定爲
3000
字節
SQL> create table TEST_LOB
2 (
3 IMAGE BLOB
4 )
5 LOB(IMAGE)
6 STORE AS TEST_IMAGE_LOB (
7 TABLESPACE zl9eprlob
8 pctversion 10 disable storage in row
chunk 3000
9 INDEX TEST_IMAGE_INDEX (
10 TABLESPACE zl9eprlob)
11 );
Table created
--
查詢
LOB
視圖,看到
Oracle
自動設置
CHINK SIZE
爲
8k
,也就是
1
倍數據塊的大小。
SQL> select chunk
2 from dba_lobs
3 where table_name='TEST_LOB'
4 and owner=USER
5 ;
CHUNK
----------
8192
須要注意,
CHUNK
僅僅對存儲在行外的
LOB
數據有效。
從上面能夠看出,
CHUNK
或
DB_BLOCK_SIZE
肯定了存儲在行外的
LOB
數據的空間分配單位。例如,
CHUNK
設置爲
32K
,且設置了
」disable storage in row」
,即便
LOB
數據只有
10
字節大小,也將在
LOB
段中分配
32K
的空間。若是
chunk
設置不合理,就可能形成空間的巨大浪費
,
也會對性能形成很差的影響。
3.4 PCTVERSION
咱們都知道Oracle
中有「一致性讀」的概念,事務提交前的「前鏡像數據」會存儲到UNDO
表空間中,若是查詢的開始時間晚於事務的開始時間,將從UNDO
表空間讀取修改前的數據,這特性被稱爲「一致性讀(Consistent Read)
」。前面說過對存儲在行外的LOB
對象,LOB
數據自己是不生產UNDO
信息的,那Oracle
如何保證LOB
對象的讀一致性呢?Oracle
爲解決這個問題,專門引入了PCTVERSION
參數,語法以下:
STORE AS ( PCTVERSION n )
這個參數能夠在建立以後進行修改,PCTVERSION
用於控制LOB
保存前鏡像數據存儲空間的百分比,保存的這些前鏡像數據就用於LOB
對象的一致性讀;這些數據保存在與LOB
段相同的表空間中,若是設置太大將使得表空間膨脹得很快。
若是一個會話嘗試讀取一個被覆蓋的LOB
前鏡像數據(緣由就是pct version
設置得過小),一樣將產生」ora-01555:
快照太舊」
的錯誤。須要說明的是pctversion
只是一個大概值,Oracle
內部有一個特殊的算法來計算保留的空間。若是系統中有針對LOB
的大量的長時間事務,就須要結合各類狀況,設置一個合理的值。
3.5 LOB
數據的緩存
Oracle
使用數據庫調整緩存來加快數據的存取速度,LOB
數據與結構化數據的緩存機制也不同,這須要引發咱們的注意,與普通的段同樣,也能夠指定CACHE
與NOCACHE
選項:
STORE AS ( CACHE ) / STORE AS ( NOCACHE )
這個選項也能夠在建立表以後經過
alter
語句進行修改。
缺省設置爲
NOCACHE
,在
NOCACHE
下,讀寫
LOB
數據將使用直接路徑讀寫,繞過數據庫高速緩存
,
直接從磁盤進行讀取;這意味着
Oracle
將不緩存
LOB
段的數據塊;若是在
AWR/STATSPACK
中發現direct path read/ direct path wirte
等待很高,就多是
LOB
對象
的讀寫引發的。
設置爲CACHE
,則LOB
的讀寫則將經過數據庫調整緩存進行;
這種方式下讀取LOB
的等待事件顯示爲
"db file sequential read",
可是不象掃描表的數據塊那樣置於
LRU
列表的「最近使用」端的末尾。
設置爲
cache
選項必定要很是當心,若是表中的
LOB
段很大,緩存這些
LOB
段就須要消耗大量的內存;若是表的
lob
段總的空間不大,且讀寫頻繁,設置爲
cache
就比較恰當。例如,咱們在實際調優過程當中,將
ZLBH
資源信息的
RESOURCEINFO
表中的序列化窗體的
LOB
列設置爲
cache
就取得了比較好的效果。
存儲在行內的
LOB
列是不受
CACHE/NOCACHE
選項影響的,存儲在行內的
LOB
數據同普通數據塊同樣,經過數據庫高速緩存進行讀寫。
CACHE/NOCACHE
選項也會對
REDO
日誌的數量產生影響。
NOCACHE
時,直接路徑讀寫
LOB
對象,整個
LOB
塊映象會寫入
REDO
中
;
而設置
CACHE
時
,
僅僅
LOB
數據塊變化時,纔會寫入到
REDO
中。例如,設置了
'DISABLE STORAGE
IN ROW NOCACHE CHUNK 32K'
的情
況下,即便
LOB
數據僅僅只有
5
個字節,也將會產生全部
32K
的
redo
記錄,若是是
cache
選項,則只產生
5
字節的
redo
記錄。
3.6 LOGGING
咱們知道
Oracle
在表、索引等數據段上,可使用
nologging
選項,來減小
REDO
產生的量,以達到提高性能的目的。在
LOB
類型中,這個選項必須依賴於
NOCACHE
選項,只有下面兩種組合:
STORE AS ( NOCACHE LOGGING )
STORE AS ( NOCACHE NOLOGGING )
也就是說在
CACHE
選項下,
Oracle
是強制使用
LOGGING
方式的;這個值缺省爲
LOGGING
。若是啓用了
NOLOGGING
,當發生數據損壞
,Oracle
須要作介質恢復時,
LOB
段將被標記爲損壞,也就是損失的
LOB
數據是沒法恢復的,緣由就是沒有產生恢復必須的
REDO
日誌。
3.7 結語
若是更新存儲在行外的LOB
數據,將會建立一個版本的LOB
前鏡像數據,這些數據是要消耗必定的存儲空間,前已有所述,這是爲了實現「一致性讀」的須要,也就是說LOB
段須要消耗比結構化數據更多的空間,才能實現事務的併發。同時在開發時,咱們能夠結合 LOB
對象的CHUNK
大小,設置數據庫驅動中一次讀取LOB
對象的緩存大小。
在不一樣的應用場景
,須要分析咱們的應用並結合
LOB
平均大小、數據塊大小、
Oracle
的內存設置等因素來綜合考慮咱們的
LOB
設置。
但願本文能給你正確使用
LOB
類型帶來幫助
!
參考資料:
Metalink: Oracle8 Example SQL Demonstrating use of LOBs in Oracle8 [ID 47740.1]
Metalink: LOBs and ORA-01555 troubleshooting [ID 846079.1]