日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

oracle t44,SecureFiles LOBs基础知识之存储篇

發布時間:2023/12/10 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 oracle t44,SecureFiles LOBs基础知识之存储篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

SecureFiles LOBs相比于BasicFiles

LOBs具有加密(encryption)、去重(deduplicaiton)、壓縮(compression)等新功能,pctversion,chunksize等參數也僅僅為了向后兼容而保留,因此SecureFiles LOBs的自適應能力更強,在管理上更為簡化,成為了clob、blob等大對象使用的首選,上面的這些功能描述可以參考官方文檔來獲得。

我們今天要討論的是SecureFiles LOBs里與存儲相關的知識,當你在使用SecureFiles LOBs的時候你是否了解它在磁盤上是如何存儲的,在創建SecureFiles LOBs時對于存儲有關的參數設定有何要求,lob如何管理自己的undo等問題,我們都將會通過實驗來為大家解答這些問題。

?Securefile LOBs字段所在數據塊的存儲結構

--建立測試用表為dump作準備

create table lobt1 (id number,c1

clob) lob(c1) store as securefile lobt1_c1(disable storage in row);

insert into lobt1

values(1,lpad('A',10,'A'));

insert into lobt1

values(2,lpad('B',10,'B'));

commit;

alter system flush buffer_cache;

select

dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','LOBT1')

absfno,dbms_rowid.rowid_block_number(rowid) blkno,count(1) from LOBT1 group by

dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','LOBT1'),dbms_rowid.rowid_block_number(rowid);

ABSFNO????? BLKNO

COUNT(1)

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

131

723110????????? 2

alter system dump datafile 131 block 723110;

-- lobt1表dump結果節選:

tab 0, row 0, @0x1f6c

tl: 44 fb: --H-FL-- lb: 0x1? cc: 2

col

0: [ 2]? c1 02

col

1: [37]

00 54 00 01 02 0c 80

80 00 0200 00 00 01 00 04 29 37 3d a5 00 11 40 90 00

0b20 00 14 01 00 00 20 cb 0f 2f 01

LOB

Locator:

Length:??????? 84(37)

Version:??????? 1

Byte Length:??? 2

LobID: 00.00.00.01.00.04.29.37.3d.a5

Flags[ 0x02 0x0c 0x80 0x80 ]:

Type: CLOB

Storage: SecureFile

Characterset Format: IMPLICIT

Partitioned Table: No

Options: VaringWidthReadWrite

SecureFile Header:

Length:?? 17

Old Flag: 0x40 [ SecureFile ]

Flag 0:?? 0x90 [ INODE Valid ]

Layers:

Lengths Array: INODE:11

INODE:

20 00 14 01 00 00 20

cb 0f 2f 01

02 0c 80 80:字段類型是clob,如果是01 0c 00 80則為blob

00 00 00 01 00 04 29 37 3d a5:每一行都有一個唯一的一個lobid

00 11:securefile

header的長度為17,從00 11開始到行尾紅17

bytes

40:表示disable

storage in row securefile,如果是48表示enable storage in row securefile

00 0b:inode長度

14:lob字段中數據所占的字節數為,0x14代表20bytes,我們插入的10個字母占用20 bytes(使用AL16UTF16字符集)

20 cb 0f 2f:chunk所在的data block

address

01:以上述chunk地址為起始地址,所包含多少個連續的chunk

?SecureFiles LOBs對表與表空間存儲參數上的要求

// 1、Maxsize的最小值測試//

--創建一個表空間extent size設置為128K

create

tablespace ts128k1 datafile '/oradata06/ts128k1.dbf' size 128M extent

management local uniform size 128K segment space management auto;

--創建帶有lob字段的表,并把lob segment的maxsize設置為512k,結果報錯

create table tlob33

(id number, t33col2 clob) lob(t33col2) store as securefile tlob_tmp (tablespace

ts128k1 storage(maxsize 512K) disable storage in

row retention max);

ERROR at line 1:

ORA-60014:

invalid MAXSIZE storage option value

create table tlob33

(id number, t33col2 clob) lob(t33col2) store as securefile tlob_tmp (tablespace

ts128k1 storage(maxsize 768K) disable storage in row retention max);

ERROR at line 1:

ORA-60014:

invalid MAXSIZE storage option value

--逐級增加maxsize的大小,來測試create語句能否成功,直到maxsize=1024k才成功

create table

tlob33 (id number,t33col2 clob) lob(t33col2) store as securefile tlob_33

(tablespace ts128k1 storage(maxsize 1024K) disable storage in row retention

max);

Table created.

--記錄lob segment的大小等信息

select

bytes,segment_name from dba_segments where segment_name='TLOB_33';

BYTES SEGMENT_NAME

----------

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

131072 TLOB_33

col segment_name

format a20

col segment_type

format a10

col

tablespace_name format a15

set linesize 150

select

segment_name,segment_type,tablespace_name,extent_id,file_id,relative_fno,block_id,blocks,bytes

from dba_extents where segment_name='TLOB_33' and tablespace_name='TS128K1';

SEGMENT_NAME??? ?????SEGMENT_TY TABLESPACE_NAME? EXTENT_ID

FILE_ID RELATIVE_FNO?? BLOCK_ID???? BLOCKS

BYTES

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

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

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

TLOB_33????????????? LOBSEGMENT TS128K1 ?????????????????0?????? 1036?????????? 13??????? 128???????? 16

131072

// 2、表空間extent_size的最小值測試//

--新創建一個表空間uniform

size縮小至64k,觀察一下securefile對extent size大小是否有要求

create

tablespace ts128k2 datafile '/oradata06/ts128k2.dbf' size 128M extent

management local uniform size 64K segment space management auto;

--下面的錯誤表明Secure

file對于表空間的extent size要求至少為112k(14*8k),而實際Extent size只有64k(8*8k),創建不成功

create table

tlob44 (id number,t44col2 clob) lob(t44col2) store as securefile tlob_44 (tablespace

ts128k2 storage(maxsize 1024K) disable storage in row retention max);

ERROR at line 1:

ORA-60019:

Creating initial extent of size 14 in tablespace of extent size 8

--新建一個表空間uniform

size設置為112k,觀察表空間的extent_size最小設為多少

create

tablespace ts128k3 datafile '/oradata06/ts128k3.dbf' size 128M extent

management local uniform size 112K segment space management auto;

--這回雖然112K了,但報了個ORA-00600錯誤

create table

tlob55 (id number,t55col2 clob) lob(t55col2) store as securefile tlob_55

(tablespace ts128k3 storage(maxsize 2128K) disable storage in row retention

max);

SQL> create

table tlob55 (id number,t55col2 clob) lob(t55col2) store as securefile tlob_55

(tablespace ts128k3 storage(maxsize 2128K) disable storage in row retention

max);

create table

tlob55 (id number,t55col2 clob) lob(t55col2) store as securefile tlob_55

(tablespace ts128k3 storage(maxsize 2128K) disable storage in row retention

max)

*

ERROR at line 1:

ORA-00600:

internal error code, arguments: [ktsladdfcb-bsz], [3], [], [], [],

[], [], [], [], [],

[], []

--測試下來最小的Extent

size必須是8k*14+1=114689,因為一定要是8k的整數倍,實際就是120K(8k*15)作為最小的extent size

drop tablespace

ts128k3 including contents and datafiles;

create

tablespace ts128k3 datafile '/oradata06/ts128k3.dbf' size 128M extent

management local uniform size 114689 segment space management auto;

Tablespace

created.

drop tablespace

ts128k3 including contents and datafiles;

create

tablespace ts128k3 datafile '/oradata06/ts128k3.dbf' size 128M extent

management local uniform size 120k segment space

management auto;

Tablespace

created.

drop table

tlob55;

create table

tlob55 (id number,t55col2 clob) lob(t55col2) store as securefile tlob_55

(tablespace ts128k3 storage(maxsize 2128K) disable storage in row retention

max);

Table created.

--下面來看一下為何oracle對存放lob

segment的extent size大小有最低要求,以第一個測試中建立的TLOB_33這個segment為例,dump一下

alter system

dump datafile 1036 block min 128 block max 143;

--從dump出來的內容里過濾出每個block的用途發現其中16個blocks中有11個是存放metadata的,我們知道lob是自己管理undo的所以這些都是存儲上花費的開銷,還有5個是存放數據用的

frmt: 0x02

chkval: 0x798b type: 0x45=NGLOB: Lob Extent Header

frmt: 0x02

chkval: 0xa7e5 type: 0x3f=NGLOB: Segment Header

frmt: 0x02

chkval: 0x798f type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x798e type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x798b type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x07f8 type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x798b type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x798b type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x7983 type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x7983 type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x7983 type: 0x3d=NGLOB: Hash Bucket

frmt: 0x02

chkval: 0x012d type: 0x00=unknown

frmt: 0x02

chkval: 0x012a type: 0x00=unknown

frmt: 0x02

chkval: 0x012b type: 0x00=unknown

frmt: 0x02 chkval:

0x0128 type: 0x00=unknown

frmt: 0x02

chkval: 0x0129 type: 0x00=unknown

結論1:securefiles LOBs的最小大小必須>=1024k,其所在表空間的最小extent

size為15個blocks,對于blocksize=8k來說,1個extent size就是120k

?SecureFiles LOBs在磁盤上的存儲方式

Securefiles LOBs存儲方式和BasicFiles LOBs一樣有兩種,一種是inline

storage,另一種是out-of-line storage。我們知道對于BasicFiles LOBs來說如果lob字段長度<=3964個字節是和表存儲在一起的,稱為inline storage;>3964字節時會遷移到lob segment里,即out-of-line storage。對于SecureFiles LOBs來說這個值是多少?我們下面測試一下。

在測試之前有個概念需要明確一下,對于CLOB類型的字段其存儲時所用的字符集有可能與數據庫本身的字符集不一致,對于使用US7ASCII、WE8ISO8859P1等定長字符集的數據庫來說clob字段存儲時使用的字符集和數據庫字符集一致;對于使用ZHS16GBK、UTF8等變長字符集的數據庫clob字段存儲時使用的字符集為UCS2(9i及以下版本)或者AL16UTF16(10g及以上版本),UCS2、AL16UTF16都是定長的,長度為2bytes,舉個例子對于字符A來說存儲到varchar2字段占用1個字節,存儲到clob字段時就會占用2個字節。以下測試數據庫使用的是ZHS16GBK字符集

//

3、SecureFiles inline storage &out-of-line storage界限測試//

--創建測試表

create table tsec_lob (id number,secol2 clob) lob(secol2)

store as securefile lob_tsec (retention);

--先插入1982個字符,每個字符兩個字節,總共占用是3964 bytes

insert into tsec_lob values(1,lpad('D',1982,'D'));

commit;

--dump出數據塊的內容

select table_name,segment_name,securefile from dba_lobs

where table_name='TSEC_LOB';

TABLE_NAME???????????????????? SEGMENT_NAME?????????????????? SEC

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

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

TSEC_LOB?????????????????????? LOB_TSEC?????????????????????? YES

select

dbms_rowid.rowid_block_number(rowid),dbms_rowid.rowid_relative_fno(rowid) from

tsec_lob;

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)

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

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

4284

302

select * from v$diag_info where name='Default Trace

File';?? --shzw1_ora_54592144.trc

alter system flush buffer_cache;

alter system dump datafile 302 block 4284;

--dump節選,目前字段總長度為3995bytes,其中前面31個bytes為metadata

block_row_dump:

tab 0, row 0, @0xff4

tl: 4004 fb: --H-FL-- lb: 0x1

cc: 2

col? 0: [ 2]? c1 02

col? 1: [3995]

00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00 04 28

c9 b5 05 0f 87 48 90 0f

81 01 00 0f 7c 0100 44 00

44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00

44 00 44 00 44 00 44

00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44

。。。。。。此處略去,一共有1982個”00 44”

--根據上面的推斷4000-31=3969,如果字段里真正數據占用的長度達到3969 bytes時就會遷移到lob segments上去,在原來基礎上增加兩個字符的長度,總長度達到3999 bytes,其中數據部分為3968 bytes,Byte Length: 2表示一個字符占據2 bytes

update tsec_lob set

secol2=lpad('D',1984,'D');

commit;

alter system flush buffer_cache;

select * from v$diag_info where

name='Default Trace File';

--shzw1_ora_24903952.trc

alter system dump datafile 302 block 4284;

--shzw1_ora_24903952.trc內容

data_block_dump,data header at 0x11085d264

===============

tsiz: 0x1f98

hsiz: 0x14

pbl: 0x11085d264

76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x4c

avsp=0xfdc

tosp=0xfdc

0xe:pti[0]????? nrow=1

offs=0

0x12:pri[0]???? offs=0x4c

block_row_dump:

tab 0, row 0, @0x4c

tl: 4008 fb: --H-FL-- lb: 0x2? cc: 2

col

0: [ 2]? c1 02

col

1: [3999]

00

54 00 01 02 0c 80 80 00 02 00 00 00 01 00 04 28 c9 b5 9b 0f 8b 48 90 0f

85

01 00 0f 80 01 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00

44

00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44

。。。省略

00

44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44 00 44

LOB

Locator:

Length:??????? 84(3999)

Version:??????? 1

Byte Length:??? 2

LobID: 00.00.00.01.00.04.28.c9.b5.9b

Flags[ 0x02 0x0c 0x80 0x80 ]:

Type: CLOB

Storage: SecureFile

Characterset Format: IMPLICIT

Partitioned Table: No

Options: VaringWidthReadWrite

SecureFile Header:

Length:?? 3979

Old Flag: 0x48 [ DataInRow SecureFile ]

Flag 0:?? 0x90 [ INODE Valid ]

Layers:

Lengths Array: INODE:3973

INODE:

--再增加一個字符的長度,發現字段會挪出table,放到數據dba:0x4b80b56f中,由此判斷securefile字節數超過3969bytes時就會從in-line storage =>out-of-line storage

update tsec_lob set

secol2=lpad('D',1985,'D');

commit;

alter system flush buffer_cache;

alter system dump datafile 302 block

4284;?? --shzw1_ora_24903952.trc

--shzw1_ora_24903952.trc內容

tab 0, row 0, @0x1f

tl: 45 fb: --H-FL-- lb: 0x1? cc: 2

col

0: [ 2]? c1 02

col

1:[38]

00

54 00 01 02 0c 80 80 00 02 00 00 00 01 00 04 28 c9 b5 9c 00 12 40 90 00

0c

21 00 0f 82 01 00 01 4b 80 b5 6f 01

LOB

Locator:

Length:??????? 84(38)

Version:??????? 1

Byte Length:??? 2

LobID: 00.00.00.01.00.04.28.c9.b5.9c

Flags[ 0x02 0x0c 0x80 0x80 ]:

Type: CLOB

Storage: SecureFile

Characterset Format: IMPLICIT

Partitioned Table: No

Options: VaringWidthReadWrite

SecureFile Header:

Length:?? 18

Old Flag: 0x40 [ SecureFile ]

Flag 0:?? 0x90 [ INODE Valid ]

Layers:

Lengths Array: INODE:12

INODE:

21 00 0f 82 01 00 01 4b 80 b5 6f 01

--將inode中的4b 80 b5 6f轉換成rdba地址,dump數據塊內容

select

dbms_utility.data_block_address_File(to_number(replace('4b 80 b5 6f','

'),'xxxxxxxx')) rfno

,dbms_utility.data_block_address_block(to_number(replace('4b 80 b5 6f','

'),'xxxxxxxx')) blkno from dual;

RFNO????? BLKNO

---------- ??----------

302????? 46447

select * from v$diag_info where

name='Default Trace File';

--shzw1_ora_3146348.trc

alter system flush buffer_cache;

alter system dump datafile 302 block

46447;

--shzw1_ora_3146348.trc內容,證明lob字段的內容已經遷移到lob

segment里

seg/obj: 0x51a682? csc: 0xb89.32fd27ef? itc: 1

flg: E? typ: 5 - LOCAL LOBS

fsl: 0? fnx: 0xffffffff ver: 0x01

Itl

Xid????????????????? Uba???????? Flag

Lck??????? Scn/Fsc

0x01

0x0406.01d.0019e032? 0x00000000.0000.00? -B--

0? fsc 0x0000.00000000

========

bdba

[0x4b80b56f]

kdlich

[11085d24c 56]

flg0? 0x20 [ver=0 typ=data lock=n]

flg1? 0x00

scn?? 0x0b89.32fd27ef

lid?? 00000001000428c9b59c

rid?? 0x00000000.0000

kdlidh

[11085d264 24]

flg2? 0x00 [ver=0 lid=short-rowid

hash=n cmap=n pfill=n]

flg3? 0x00

pskip 0

sskip 0

hash

0000000000000000000000000000000000000000

hwm?? 3970

spr?? 0

data? [11085d280 52 8060]

00 44 00 44 00 44 00 44 00 44 00 44 00 44

00 44 00 44 00 44 00 44 00 44 00 44

00 44 00 44 00 44 00 44 00 44 00 44 00 44

00 44 00 44 00 44 00 44 00 44 00 44

。。。省略

00 44 00 44 00 44 00 44 00 44 00 44 00 44

00 44 00 44 00 4f 00 47 00 56 00 41

結論2:securefiles LOBs inline存儲的字節數為<=3969

bytes,>3969 bytes時會整體遷移到lobsegment里,注意對于CLOB而言這個字節數僅僅表示存儲上所占用的空間,具體對應多少個字符,還要根據數據庫所采用的字符集來確定,對于ZHS16GBK等變長字符集的數據庫來說,1個字符在存儲上要占用兩個字節,所以字符數<=1984時為inline存儲,>1984時為out-of-line存儲,對于其它定長字符集的數據庫則不存在這個轉換關系,對于BLOB類型的字段由于存儲的都是二進制數據所以也無需進行換算

?如何通過chunk

address找到SecureFiles LOBs

SecureFiles LOBs是以chunk為單位存儲的,要找到chunk必須先有chunk

address,chunk address的存放有直接和間接兩種方式,直接方式是指chunk address就保存在表里,通過這個chunk address能直接找到包含數據的chunk,但當一個SecureFiles LOBs較大且占用的空間連續性不是很好的時候就會以間接方式存放,間接方式是指表里的block指向包含chunk address列表的另外一個block,由這另外一個block去指向包含數據的chunk。看下面的圖就很清楚了。

//

4、直接方式尋址//

--創建測試表,disable storage in row

create

tablespace lobtest_out datafile '/oradata06/lobtest_out.dbf' size 128m extent

management local uniform size 128k segment space management auto;

drop table

tout_lob;

create table

tout_lob (id number,outcol2 clob) lob(outcol2) store as securefile lob_out

(tablespace lobtest_out disable storage in row retention);

--為了能占用較多的chunk,采用loadclobfromfile將文本文件內容導入的方式,impmd.log.load.lob文件大小為1571061字節,使用存儲過程進行導入

declare

v_bfile

bfile:=bfilename('HISDMP','impmd.log.load.lob');

v_clob clob;

ncycle

integer:=1;

i integer:=1;

v_dest_offset

integer:=1;

v_src_offset

integer:=1;

v_lang_context

integer:=0;

v_warning

integer;

begin

dbms_lob.fileopen(v_bfile);

v_clob:=empty_clob();

dbms_lob.createtemporary(v_clob,FALSE,dbms_lob.session);

dbms_lob.loadclobfromfile(v_clob,v_bfile,amount=>dbms_lob.lobmaxsize,dest_offset=>v_dest_offset,src_offset=>v_src_offset,bfile_csid=>0,lang_context=>v_lang_context,warning=>v_warning);

while ( i <=

ncycle)

loop

insert into

tout_lob values(i,v_clob);

i:=i+1;

end loop;

dbms_lob.fileclose(v_bfile);

end;

/

--導入完成后對表進行dump

select * from

v$diag_info where name='Default Trace File';

--shzw1_ora_53936650.trc

alter system

flush buffer_cache;

select dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','TOUT_LOB')

absfno,dbms_rowid.rowid_relative_fno(rowid)

rfno,dbms_rowid.rowid_block_number(rowid) blkno,count(1) from tout_lob group by

dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','TOUT_LOB'),dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid);

ABSFNO

RFNO????? BLKNO?? COUNT(1)

----------

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

115??????? 115

441493????????? 1

select

id,dbms_lob.getlength(outcol2) from tout_lob;

ID

DBMS_LOB.GETLENGTH(OUTCOL2)

----------

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

1???????????????????? 1571061

alter system

dump datafile 115 block 441493;

--shzw1_ora_53936650.trc

dump內容,其中03 80 02 a1記錄的是包含chunk地址列表的dba地址

tab 0, row 0,

@0x1f6d

tl: 43 fb:

--H-FL-- lb: 0x1? cc: 2

col? 0: [ 2]

c1 02

col? 1: [36]

00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00

04 28 c9 b8 ed 00 10 40 90 00

0a 42 00 2f f1 ea 01 03

80 02 a1

LOB

Locator:

Length:

84(36)

Version:??????? 1

Byte Length:??? 2

LobID: 00.00.00.01.00.04.28.c9.b8.ed

Flags[ 0x02 0x0c 0x80 0x80 ]:

Type: CLOB

Storage: SecureFile

Characterset Format: IMPLICIT

Partitioned Table: No

Options: VaringWidthReadWrite

SecureFile Header:

Length:

16

Old Flag: 0x40 [ SecureFile ]

Flag 0:

0x90 [ INODE Valid ]

Layers:

Lengths Array: INODE:10

INODE:

42 00 2f f1 ea 01 03 80 02 a1

--將03 80 02 a1轉換為rdba地址

select

dbms_utility.data_block_address_File(to_number(replace('03 80 02 a1',' '),'xxxxxxxx'))

rfno ,dbms_utility.data_block_address_block(to_number(replace('03 80 02 a1','

'),'xxxxxxxx')) blkno from dual;

RFNO

BLKNO

----------

----------

14??????? 673

select

name,file#,rfile# from v$datafile where rfile#=14;

NAME???? ?????????????????????????????????????FILE#???? RFILE#

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

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

/oradata02/undo/undo202.dbf????????????????????? 14???????? 14

/oradata06/lobtest_out.dbf???????????????????? 1037???????? 14

---證明1037/673位于lob segment

select

segment_name,segment_type,tablespace_name,extent_id,file_id,relative_fno,block_id,blocks,bytes

from dba_extents where segment_name='LOB_OUT' and block_id<=673 and

block_id+blocks>=673;

SEGMENT_NAME???????? SEGMENT_TY TABLESPACE_NAME ?EXTENT_ID

FILE_ID RELATIVE_FNO

BLOCK_ID???? BLOCKS????? BYTES

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

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

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

LOB_OUT????????????? LOBSEGMENT LOBTEST_OUT???????????? 33?????? 1037

14??????? 672???????? 16

131072

--對1037/673進行dump的結果顯示一共使用了390個block,從dba:0x038000a7開始

select * from

v$diag_info where name='Default Trace File';

--shzw1_ora_8652048.trc

alter system

dump datafile 1037 block 673; --shzw1_ora_8652048.trc

--shzw1_ora_8652048.trc

dump內容節選

Itl

Xid????????????????? Uba???????? Flag

Lck??????? Scn/Fsc

0x01?? 0x0405.018.00165fd5? 0x0105a321.128c.10? ----

1? fsc 0x0000.00000000

========

bdba??? [0x038002a1]

kdlich? [11085d24c 56]

flg0

0x18 [ver=0 typ=lhb lock=y]

flg1

0x00

scn

0x0b89.32fddadb

lid

00000001000428c9b8ed

rid

0x00000000.0000

kdlihh? [11085d264 24]

flg2

0x00 [ver=0 lid=short-rowid hash=n it=n bt=n xfm=n ovr=n aux=n]

flg3

0x80 [vll=y]

flg4

0x00

flg5

0x00

hash

0000000000000000000000000000000000000000

llen

0.3142122

ver

0.1

#ext

40

asiz

40

hwm

40

ovr

0x00000000.0

dba0

0x00000000

dba1

0x00000000

dba2

0x00000000

dba3

0x00000000

auxp

0x00000000

ldba

0x03800251

nblk? 390

[0] 0x00 0x00 9 0x038000a7

[1] 0x00 0x00 3 0x038000bd

[2] 0x00 0x00 2 0x038000a5

[3] 0x00 0x00 15 0x038000c1

[4] 0x00 0x00 9 0x038000d7

[5] 0x00 0x00 6 0x038000d1

[6] 0x00 0x00 9 0x038000e7

[7] 0x00 0x00 6 0x038000e1

[8] 0x00 0x00 9 0x038000f7

[9] 0x00 0x00 6 0x038000f1

[10] 0x00 0x00 15 0x03800101

[11] 0x00 0x00 9 0x03800117

[12] 0x00 0x00 6 0x03800111

[13] 0x00 0x00 9 0x03800127

[14] 0x00 0x00 6 0x03800121

[15] 0x00 0x00 9 0x03800137

[16]

0x00 0x00 6 0x03800131

[17] 0x00 0x00 9 0x03800147

[18] 0x00 0x00 6 0x03800141

[19] 0x00 0x00 15 0x03800151

[20] 0x00 0x00 15 0x03800161

[21] 0x00 0x00 9 0x03800177

[22] 0x00 0x00 6 0x03800171

[23] 0x00 0x00 9 0x03800187

[24] 0x00 0x00 6 0x03800181

[25] 0x00 0x00 15 0x03800191

[26] 0x00 0x00 9 0x038001a7

[27] 0x00 0x00 6 0x038001a1

[28] 0x00 0x00 15 0x038001b1

[29] 0x00 0x00 9 0x038001c7

[30] 0x00 0x00 6 0x038001c1

[31] 0x00 0x00 15 0x038001d1

[32] 0x00 0x00 15 0x038001e1

[33] 0x00 0x00 15 0x03800201

[34] 0x00 0x00 15 0x038001f1

[35] 0x00 0x00 15 0x03800211

[36] 0x00 0x00 15 0x03800221

[37] 0x00 0x00 15 0x03800231

[38] 0x00 0x00 15 0x03800241

[39] 0x00 0x00 1 0x03800251

--dump一下0x038000a7的內容,包含的就是impmd.log.load.lob文件開頭的4030個字符

alter system

dump datafile 1037 block 167; --shzw1_ora_54067770.trc

--dump內容節選:

hwm

8060

spr?? 0

data

[11085d280 52 8060]

00 0a 00 43 00

6f 00 6e 00 6e 00 65 00 63 00 74 00 65 00 64 00 20 00 74 00 6f

00 3a 00 20 00

4f 00 72 00 61 00 63 00 6c 00 65 00 20 00 44 00 61 00 74 00 61

//

5、滿足什么條件會采用間接方式尋址//

--新建測試表,準備好大小為82957

bytes的文本文件impmd.log.load.12c1

drop table

tout_lob;

create table

tout_lob (id number,outcol2 clob) lob(outcol2) store as securefile lob_out

(tablespace lobtest_out disable storage in row retention);

--執行存儲過程用impmd.log.load.12c1文件填充lob字段

declare

v_bfile

bfile:=bfilename('HISDMP','impmd.log.load.12c1');

v_clob clob;

ncycle

integer:=1;

i integer:=1;

v_dest_offset

integer:=1;

v_src_offset

integer:=1;

v_lang_context

integer:=0;

v_warning

integer;

begin

dbms_lob.fileopen(v_bfile);

v_clob:=empty_clob();

dbms_lob.createtemporary(v_clob,FALSE,dbms_lob.session);

dbms_lob.loadclobfromfile(v_clob,v_bfile,amount=>dbms_lob.lobmaxsize,dest_offset=>v_dest_offset,src_offset=>v_src_offset,bfile_csid=>0,lang_context=>v_lang_context,warning=>v_warning);

while ( i <=

ncycle)

loop

insert into

tout_lob values(i,v_clob);

i:=i+1;

end loop;

dbms_lob.fileclose(v_bfile);

end;

/

--填充后dump

tout_lob表內容

select * from

v$diag_info where name='Default Trace File';

--shzw1_ora_11994174.trc

alter system

flush buffer_cache;

select

dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','TOUT_LOB') absfno,dbms_rowid.rowid_relative_fno(rowid)

rfno,dbms_rowid.rowid_block_number(rowid) blkno,count(1) from tout_lob group by

dbms_rowid.rowid_to_absolute_fno(rowid,'SCOTT','TOUT_LOB'),dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid);

ABSFNO

RFNO????? BLKNO?? COUNT(1)

----------

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

441??????? 441

17562????????? 1

alter system

dump datafile 441 block 17562;

--shzw1_ora_11994174.trc內容,一共使用了21個blocks,分別是0x038000a9起始的7個blocks、0x038000bd起始的3個blocks、0x038000a5起始的4個blocks、0x038000ca起始的6個block、0x038000c1起始的1個block,采用的是直接尋址的方式

tab 0, row 0,

@0x1f52

tl: 70 fb:

--H-FL-- lb: 0x1? cc: 2

col? 0: [ 2]

c1 02

col? 1: [63]

00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00

04 28 ca e5 51 00 2b 40 90 00

25 22 00 02 88 1a 01 04 01 03 80 00 a9 07 01 03 80 00 bd 03 01 03 80 00 a5

04 01 03 80 00 ca 06 01 03 80 00 c1 01

--為了模擬出間接尋址的情況,使用如下過程往lob字段里每次增加4000字符,每個字符占用兩個字節,所以每追加一次最多只會占用一個block,便于我們觀察效果

select

id,dbms_lob.getlength(outcol2) from tout_lob;

ID DBMS_LOB.GETLENGTH(OUTCOL2)

----------

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

182957

--下面的過程執行6次,每次執行后都dump一下觀察是否轉為了間接尋址

declare

v_buffer

varchar2(6000):=lpad('AB',4000,'AB');

v_clob clob;

i integer:=0;

ncycle

integer:=1;

begin

select outcol2

into v_clob from tout_lob for update;

while (i <

ncycle) loop

dbms_lob.writeappend(v_clob,4000,v_buffer);

i:=i+1;

end loop;

commit;

end;

/

--最新一次執行后的dump結果結果如下,blocks數量已經增加到了27個,表里存放的

chunk address數量已經達到了6個,使用的還是直接尋址:

select * from

v$diag_info where name='Default Trace File'; --shzw1_ora_11994176.trc

alter system

dump datafile 441 block 17562;

tab 0, row 0,

@0x1f06

tl: 76 fb:

--H-FL-- lb: 0x1? cc: 2

col? 0: [ 2]

c1 02

col? 1: [69]

00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00

04 28 ca e5 51 00 31 40 90 00

2b 22 00 03 43 9a 07 05 01 03 80 00 a9 07 01 03 80 00 bd0301 03 80 00 a5

04 01 03 80 00 ca 06 01 03 80 00 c1 02 01 03 80 00 c4 05

**最后再執行一次存儲過程后,dump

441/17562的結果里終于呈現出間接尋址的跡象了

--再執行一次過程

declare

v_buffer

varchar2(6000):=lpad('AB',4000,'AB');

v_clob clob;

i integer:=0;

ncycle

integer:=1;

begin

select outcol2

into v_clob from tout_lob for update;

while (i <

ncycle) loop

dbms_lob.writeappend(v_clob,4000,v_buffer);

i:=i+1;

end loop;

commit;

end;

/

--block

441/17562 dump結果,明顯可以看出地址變短了,原來存放的6個chunk address變成了0x038000e1這一個地址

tab 0, row 0,

@0x1edb

tl: 43 fb:

--H-FL-- lb: 0x2? cc: 2

col? 0: [ 2]

c1 02

col? 1: [36]

00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00

04 28 ca e5 51 00 10 40 90 00

0a 42 00 03 df da 08 03

80 00 e1

LOB

Locator:

Length:

84(36)

Version:??????? 1

Byte Length:??? 2

LobID: 00.00.00.01.00.04.28.ca.e5.51

Flags[ 0x02 0x0c 0x80 0x80 ]:

Type: CLOB

Storage: SecureFile

Characterset Format: IMPLICIT

Partitioned Table: No

Options: VaringWidthReadWrite

SecureFile Header:

Length:

16

Old Flag: 0x40 [ SecureFile ]

Flag 0:

0x90 [ INODE Valid ]

Layers:

Lengths Array: INODE:10

INODE:

42 00 03 df da 08 03 80 00 e1

-- dba:0x038000e1的dump結果顯示該塊中包含了前面直接尋址時的chunk地址,

Object id on Block? Y

seg/obj: 0x51a69a? csc: 0xb89.32fe6c01? itc: 1

flg: E? typ: 5 - LOCAL LOBS

fsl: 0

fnx: 0xffffffff ver: 0x01

Itl

Xid????????????????? Uba???????? Flag

Lck??????? Scn/Fsc

0x01?? 0x03fb.012.001414b3? 0x030693ac.fae5.07? ----

1? fsc 0x0000.00000000

========

bdba??? [0x038000e1]

kdlich? [11085d24c 56]

flg0

0x18 [ver=0 typ=lhb lock=y]

flg1

0x00

scn

0x0b89.32fe6c01

lid

00000001000428cae551

rid

0x00000000.0000

kdlihh? [11085d264 24]

flg2

0x00 [ver=0 lid=short-rowid hash=n it=n bt=n xfm=n ovr=n aux=n]

flg3

0x80 [vll=y]

flg4

0x00

flg5

0x00

hash

0000000000000000000000000000000000000000

llen

0.253914

ver

0.8

#ext? 9

asiz? 9

hwm?? 9

ovr

0x00000000.0

dba0

0x00000000

dba1

0x00000000

dba2

0x00000000

dba3

0x00000000

auxp

0x00000000

ldba

0x038000c9

nblk

32

[0] 0x00 0x00 7 0x038000a9

[1] 0x00 0x00 3 0x038000bd

[2] 0x00 0x00 4 0x038000a5

[3] 0x00 0x00 6 0x038000ca

[4] 0x00 0x00 2 0x038000c1

[5] 0x00 0x00 5 0x038000c4

[6] 0x00 0x00 1 0x038000c3

[7] 0x00 0x00 3 0x038000dd

[8] 0x00 0x00 1 0x038000c9

但dba:0x038000e1這個起到地址索引效果的塊位于lob segment里,并不在lob index里,oracle何時會使用lob index有待進一步考證

結論3:當表里直接尋址的chunk Address地址數大于6個時,會轉換為間接尋址的模式

?SecureFiles LOBs的read consistency特性

當lob字段和表中其它非lob字段分開存放的時候,lob字段的讀一致性實現依賴于lob

segment本身,所有的修改前鏡像會保存在lob segment里,和undo表空間沒有任何關系,這樣設計也是為了避免lob字段過大時產生的before-image過大從而影響undo表空間中的其它非lob對象的讀一致性。Lob segment自己的讀一致性管理機制由LOB_retention_clause所定義的值決定,這個值在建表的時候指定,之后也可以使用alter table進行修改,retention有以下四種取值,

MAX:在lob segment達到最大值之后,才開始覆蓋before-image所占用的block,前提是在建lob

segment時必須指定maxsize;

MIN:數據庫工作在閃回模式下,限定特定的lob

segment能夠閃回到多久時間以前的狀態

AUTO:before-image的保留時間參照數據庫的undo_retention參數

NONE:不保存before-image,用于不需要讀一致性的環境

深入lob讀一致性之前,我們先要了解一下一個lob segment中的數據塊有哪些類型,MOS 1453350.1中提供了check_space_securefile存儲過程,里面封裝的是DBMS_SPACE.SPACE_USAGE,用來檢測lob segment中數據塊的使用情況。以owner和lobsegment名作為輸入,例如:exec check_space_securefile('SCOTT','TLOB_AUTO');輸出為:

Segment Blocks/Bytes?? = 64 / 524288

Unused

Blocks/Bytes??? = 34 / 278528

Used

Blocks/Bytes????? = 8 / 65536

Expired

Blocks/Bytes?? = 13 / 106496

Unexpired

Blocks/Bytes = 9 / 73728

==========================================================================

NON Data

Blocks/Bytes? = 56 / 458752

它將數據塊分為unused、used、expired、unexpired四種,

Unused block:這個命名有點誤導,指的是起到存放metadata的block,諸如:Segment Header、CFS Hash Bucket、Committed Free Space、Uncommit Free Space、Persistent Undo,這些類型的的block都是lob segment所特有的,既然能有自己的讀一致性機制這些控制信息必不可少。所以Unused block并非指空閑的數據塊。

Used block:已經包含有用戶數據的block

Expired block:空閑的數據庫塊(包括從未被使用的和曾經被使用過但按照現有的retention策略可以被覆蓋使用的)

Unexpired blocks:存放修改前鏡像,為滿足讀一致性需要暫時保留不能被覆蓋的數據塊

以上輸出中的NON Data Blocks是將segment_blocks-used_blocks而得到

我們分別體驗一下MAX、AUTO、NONE三個參數的作用

//

6、retention MAX ?//

###先測試一下在沒有達到maxsize的情況下,修改前鏡像會一直保留著

--建表,指定lob segment最大為1024k

drop table tlob44;

create table tlob44 (id number,t44col2 clob) lob(t44col2)

store as securefile tlob_44 (tablespace ts128k3 storage(maxsize

1024K) disable storage in row retention max);

--插入若干條記錄

declare

v_str varchar2(6000);

i number;

j number;

begin

i:=101;

j:=1;

while ( i < 123 ) loop

v_str:=lpad(chr(i),6000,chr(i));

insert into tlob44 values(j,v_str);

i:=i+1;

j:=j+1;

end loop;

commit;

end;

/

--觀察lob segment的空間使用情況

exec check_space_securefile('SCOTT','TLOB_44');

Segment Blocks/Bytes?? = 96 / 786432

Unused Blocks/Bytes??? = 36 / 294912

Used Blocks/Bytes????? = 45 / 368640

Expired Blocks/Bytes?? = 15 / 122880

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes

= 51 / 417792

--刪除其中id<10的9條記錄,有18個block變成了unexpired

delete tlob44 where id<10;

commit;

exec

check_space_securefile('SCOTT','TLOB_44');

Segment Blocks/Bytes?? = 96 / 786432

Unused Blocks/Bytes??? = 36 / 294912

Used Blocks/Bytes????? = 27 / 221184

Expired Blocks/Bytes?? = 15 / 122880

Unexpired Blocks/Bytes = 18 / 147456

===========================================================================

NON Data Blocks/Bytes

= 69 / 565248

--再插入9條記錄,由于沒有達到maxsize所以unexpired blocks不會被重用

declare

v_str varchar2(6000);

i number;

j number;

begin

i:=98;

j:=1;

while ( i < 107 ) loop

v_str:=lpad(chr(i),6000,chr(i));

insert into tlob44 values(j,v_str);

i:=i+1;

j:=j+1;

end loop;

commit;

end;

/

---unexpired blocks依然保持18個,新進來的數據使用新分配的空間

exec

check_space_securefile('SCOTT','TLOB_44');

Segment Blocks/Bytes?? = 112 / 917504

Unused Blocks/Bytes??? = 37 / 303104

Used Blocks/Bytes????? = 45 / 368640

Expired Blocks/Bytes?? = 12 / 98304

Unexpired Blocks/Bytes = 18 / 147456

===========================================================================

NON Data Blocks/Bytes? = 67 / 548864

###接著測試在達到maxsize的情況下,如果有新進數據會覆蓋修改前鏡像

drop table tlob33;

create table tlob33 (id number,t33col2 clob) lob(t33col2)

store as securefile tlob_33 (tablespace ts128k3 storage(maxsize

1024K) disable storage in row retention max);

--插入44行記錄,都是大小寫英文字母,每行6000個字符,占據2個blocks

declare

v_str

varchar2(6000);

j

number:=1;

i number;

begin

i:=101;

while ( i

< 123 ) loop

v_str:=lpad(chr(i),6000,chr(i));

insert

into tlob33 values(j,v_str);

i:=i+1;

j:=j+1;

end loop;

i:=65;

while ( i

< 87 ) loop

v_str:=lpad(chr(i),6000,chr(i));

insert

into tlob33 values(j,v_str);

i:=i+1;

j:=j+1;

end loop;

commit;

end;

/

--統計space usage,還剩1個空閑的block

exec

check_space_securefile('SCOTT','TLOB_33');

Segment

Blocks/Bytes?? = 128 / 1048576

Unused

Blocks/Bytes??? = 38 / 311296

Used

Blocks/Bytes????? = 89 / 729088

Expired Blocks/Bytes

= 1/ 8192

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes

= 39 / 319488

--只能再插入一個block,插入第二個block時就報錯了,因為已經達到1024k上限了,說明maxsize設置生效

declare

v_str45

varchar2(3000):=lpad('S',3000,'S');

begin

insert into

tlob33 values(45,v_str45);

commit;

end;

/

PL/SQL procedure

successfully completed.

declare

v_str46

varchar2(3000):=lpad('T',3000,'T');

begin

insert into

tlob33 values(46,v_str46);

commit;

end;

/

ERROR at line 1:

ORA-60010:

adding (144) blocks to LOB segment SCOTT.TLOB_33 with MAXSIZE (128)

ORA-06512: at

line 4

--expired block=0說明沒有空閑空間來容納新的記錄

SQL> exec

check_space_securefile('SCOTT','TLOB_33');

Segment

Blocks/Bytes?? = 128 / 1048576

Unused

Blocks/Bytes??? = 38 / 311296

Used

Blocks/Bytes????? = 90 / 737280

Expired

Blocks/Bytes?? = 0 / 0

Unexpired

Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes

= 38 / 311296

select

bytes,segment_name from dba_segments where segment_name='TLOB_33';

BYTES

SEGMENT_NAME

----------

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

1048576 TLOB_33

-- session 2:為測試一致性讀另開的

set transaction read only;

--刪除剛剛插入的id=45的記錄,釋放出一個block

delete tlob33 where id=45;

commit;

--刪除的記錄放在Unexpired Blocks里

exec

check_space_securefile('SCOTT','TLOB_33');

Segment

Blocks/Bytes?? = 128 / 1048576

Unused

Blocks/Bytes??? = 38 / 311296

Used

Blocks/Bytes????? = 89 / 729088

Expired

Blocks/Bytes?? = 0 / 0

Unexpired Blocks/Bytes = 1 / 8192

--session 2能一致性讀到id=45的記錄,

select

id,dbms_lob.getlength(t33col2) from tlob33 where id=45;

ID DBMS_LOB.GETLENGTH(T33COL2)

----------

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

45??????????????????????? 3000

--往tlob33表中再次插入一條記錄,unexpired的block會被重用

declare

v_str47 varchar2(3000):=lpad('U',3000,'U');

begin

insert into

tlob33 values(47,v_str47);

commit;

end;

/

--unexpired blocks變為0,Used Blocks增加1

exec check_space_securefile('SCOTT','TLOB_33');

Segment Blocks/Bytes?? = 128 /

1048576

Unused Blocks/Bytes??? = 38 /

311296

Used Blocks/Bytes????? = 90 /

737280

Expired Blocks/Bytes?? = 0 / 0

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 38 /

311296

--session 2,再次查詢tlob33收到ORA-1555錯誤:

select * from tlob33 where id=45;

ERROR:

ORA-01555: snapshot too old: rollback segment number? with name "" too small

ORA-22924: snapshot too old

select count(*) from tlob33 where id<45;

COUNT(*)

----------

44

--繼續刪除id<3的記錄

delete tlob33 where id<3;

2 rows deleted.

commit;

--空出來4個blocks

exec check_space_securefile('SCOTT','TLOB_33');

Segment Blocks/Bytes?? = 128 /

1048576

Unused Blocks/Bytes??? = 38 /

311296

Used Blocks/Bytes????? = 86 /

704512

Expired Blocks/Bytes?? = 0 / 0

Unexpired Blocks/Bytes = 4 / 32768

===========================================================================

NON Data Blocks/Bytes? = 42 /

344064

--session 2中能一致性讀到這兩條記錄

select count(*) from tlob33 where id<3;

COUNT(*)

----------

2

--往tlob33表中再次插入一條記錄,4個expired blocks里有兩個會被重用,根據先進先出的原則被重用的應該是先插入的id=1的記錄所在的block被覆蓋

declare

v_str48 varchar2(6000):=lpad('V',6000,'V');

begin

insert into tlob33 values(48,v_str48);

commit;

end;

/

--session 2,測試結果驗證了上面的結論:id=1的記錄不能讀取,id=2的記錄能讀到

SQL>select count(*) from tlob33 where id<3;

ERROR:

ORA-01555: snapshot too old: rollback segment number? with name "" too small

ORA-22924: snapshot too old

SQL> select * from tlob33 where id=1;

ERROR:

ORA-01555: snapshot too old: rollback segment number? with name "" too small

ORA-22924: snapshot too old

SQL> select * from tlob33 where id=2;

ID

----------

T33COL2

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

2

ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

結論4:retention=max時當lob segment大小增加到maxsize值時,會挪用unexpired

blocks作為可用空間存放新入數據,挪用unexpired blocks時遵循先進先出的原則,即優先覆蓋較早生成的block。在未觸及maxsize的情況下修改前鏡像會一直保留著。

//

7、retention AUTO ?//

--設置undo_retention=90,retention auto時會參照undo_retention設置時間保留修改前鏡像

alter system set undo_retention=90;

SQL> show parameter

undo_retention

NAME???????????????????????????????? TYPE??????? VALUE

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

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

undo_retention?????????????????????? integer???? 90

--創建測試表

create table tlobauto (id

number,autocol2 clob) lob(autocol2) store as securefile tlob_auto

(tablespace ts128k1 storage(maxsize

1024K) disable storage in row retention auto);

--檢查空間使用情況

Set serveroutput on

exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 16 / 131072

Unused Blocks/Bytes??? = 11 / 90112

Used Blocks/Bytes????? = 0 / 0

Expired Blocks/Bytes?? = 5 / 40960

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 16 / 131072

--填充16行,每行50個字符

declare

v_str_length integer:=50;?? --指定隨機字串的單位長度

v_nrows integer:=16;????????????? --指定插入行數

v_conn_num integer:=1;?????? --指定隨機字串的單元數

i integer:=0;

j integer:=0;

v_str varchar2(32767);

begin

while (i < v_nrows) loop

v_str:=dbms_random.string('U',v_str_length);

while (j < v_conn_num-1) loop

v_str:=v_str||dbms_random.string('U',v_str_length);

j:=j+1;

end loop;

dbms_output.put_line(length(v_str));

insert into tlobauto

values(i,v_str);

commit;

i:=i+1;

j:=0;

end loop;

commit;

end;

/

--17個used block,13個expired

blocks

SQL> exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used Blocks/Bytes????? = 17 / 139264

Expired Blocks/Bytes?? = 13 / 106496

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 47 / 385024

--刪除id<5的5行記錄

Delete tlobauto where id<5;

Commit;

--5個unexpired blocks,存放了被刪除的5行記錄

SQL> exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used Blocks/Bytes????? = 12 / 98304

Expired Blocks/Bytes?? = 13 / 106496

Unexpired Blocks/Bytes = 5 / 40960

===========================================================================

NON Data Blocks/Bytes? = 52 / 425984

--等待90秒后再檢驗,unexpired

blocks為0,5個blocks都加到了expired blocks上面

SQL> exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used Blocks/Bytes????? = 12 / 98304

Expired Blocks/Bytes?? = 18 / 147456

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 52 / 425984

--上面的結果看似驗證了retention

auto時before-image在lob segment里的保留時間跟隨undo_retention的設置,但這也不是絕對的,比如下面的場景

--重新建立表tlobauto

Drop table tlobauto;

create table tlobauto (id

number,autocol2 clob) lob(autocol2) store as securefile tlob_auto

(tablespace ts128k1 storage(maxsize

1024K) disable storage in row retention auto);

--初始空間使用情況

exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 16 / 131072

Unused Blocks/Bytes??? = 11 / 90112

Used Blocks/Bytes????? = 0 / 0

Expired Blocks/Bytes?? = 5 / 40960

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 16 / 131072

--修改undo_retention為7200

Alter system set undo_retention=7200

scope=memory;

SQL> show parameter

undo_retention

NAME???????????????????????????????? TYPE??????? VALUE

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

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

undo_retention??????????????????? ???integer

7200

--第一輪填充tlobauto表,16行,每行50個字符

set serveroutput on

declare

v_str_length integer:=50;?? --指定隨機字串的單位長度

v_nrows integer:=16;????????????? --指定插入行數

v_conn_num integer:=1;?????? --指定隨機字串的單元數

i integer:=0;

j integer:=0;

v_str varchar2(32767);

begin

while (i < v_nrows) loop

v_str:=dbms_random.string('U',v_str_length);

while (j < v_conn_num-1) loop

v_str:=v_str||dbms_random.string('U',v_str_length);

j:=j+1;

end loop;

dbms_output.put_line(length(v_str));

insert into tlobauto values(i,v_str);

commit;

i:=i+1;

j:=0;

end loop;

commit;

end;

/

--check space usage

exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used Blocks/Bytes????? = 17 / 139264

Expired Blocks/Bytes?? = 13 / 106496

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 47 / 385024

--刪除9行記錄

delete tlobauto where id>6 and

id<16;

commit;

--check space usage

exec check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used Blocks/Bytes????? = 8 / 65536

Expired Blocks/Bytes?? = 13 / 106496

Unexpired Blocks/Bytes = 9 / 73728

===========================================================================

NON Data Blocks/Bytes? = 56 / 458752

--第二輪繼續填充tlobauto表,插入11行,每行50個字符

set serveroutput on

declare

v_str_length integer:=50;?? --指定隨機字串的單位長度

v_nrows integer:=18;????????????? --指定插入行數

v_conn_num integer:=1;?????? --指定隨機字串的單元數

i integer:=7;

j integer:=0;

v_str varchar2(32767);

begin

while (i < v_nrows) loop

v_str:=dbms_random.string('U',v_str_length);

while (j < v_conn_num-1) loop

v_str:=v_str||dbms_random.string('U',v_str_length);

j:=j+1;

end loop;

dbms_output.put_line(length(v_str));

insert into tlobauto

values(i,v_str);

commit;

i:=i+1;

j:=0;

end loop;

commit;

end;

/

--check space usage發現used blocks從8增加到了19,expired

blocks從13下減到了11

exec check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 64 / 524288

Unused Blocks/Bytes??? = 34 / 278528

Used

Blocks/Bytes????? = 19/ 155648

Expired

Blocks/Bytes?? = 2/ 16384

Unexpired Blocks/Bytes = 9 / 73728

===========================================================================

NON Data Blocks/Bytes? = 45 / 368640

--第三輪又插入三行記錄,每行50個字符

set serveroutput on

declare

v_str_length integer:=50;?? --指定隨機字串的單位長度

v_nrows integer:=21;????????????? --指定插入行數

v_conn_num integer:=1;?????? --指定隨機字串的單元數

i integer:=18;

j integer:=0;

v_str varchar2(32767);

begin

while (i < v_nrows) loop

v_str:=dbms_random.string('U',v_str_length);

while (j < v_conn_num-1) loop

v_str:=v_str||dbms_random.string('U',v_str_length);

j:=j+1;

end loop;

dbms_output.put_line(length(v_str));

insert into tlobauto

values(i,v_str);

commit;

i:=i+1;

j:=0;

end loop;

commit;

end;

/

--最終檢查空間使用情況發現雖然沒有達到undo_retention所指定的7200秒,lob segment也沒有達到其maxsize所定義的上限值1024k,但還是挪用了1個unexpired

blocks,unexpired blocks從9減少到了8,可見在retention auto的情況下并不是完全聽從undo_retention的指揮,為何會出現這種情況還下不了結論,但至少證明了retention auto并不像文檔中說的那么簡單,還是有自己的一套算法

exec

check_space_securefile('SCOTT','TLOB_AUTO');

Segment Blocks/Bytes?? = 80 / 655360

Unused Blocks/Bytes??? = 35 / 286720

Used Blocks/Bytes????? = 22 / 180224

Expired Blocks/Bytes?? = 15 / 122880

Unexpired

Blocks/Bytes = 8/ 65536

===========================================================================

NON Data Blocks/Bytes? = 58 / 475136

結論5:retention auto的情況下before-image的保留時間不完全遵循與undo_retention參數的設定值,可能會引起ORA-01555錯誤

//

8、retention none ?//

--retention none比較好理解就是永遠不保存修改前的鏡像,這種情況下無法實現read consistency

create table tlobnone (id number,nonecol2 clob) lob(nonecol2)

store as securefile tlob_none (tablespace ts128k1 storage(maxsize 1024K)

disable storage in row retention none);

insert into tlobnone values(1,'A');

commit;

--插入一行后空間使用情況

exec check_space_securefile('SCOTT','TLOB_NONE');

Segment Blocks/Bytes?? = 48 / 393216

Unused Blocks/Bytes??? = 33 / 270336

Used Blocks/Bytes????? = 2 / 16384

Expired Blocks/Bytes?? = 13 / 106496

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 46 / 376832

--session 2:測試一致性讀所開的session

Set transaction read only

Select * from tlobnone where id=1;

ID

----------

NONECOL2

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

1

A

--刪除這唯一的一行

Delete tlobnone where id=1;

Commit;

--unexpired blocks為0,被刪除的數據對應的block直接歸到了空閑的block里

SQL> exec check_space_securefile('SCOTT','TLOB_NONE');

Segment Blocks/Bytes?? = 48 / 393216

Unused Blocks/Bytes??? = 33 / 270336

Used Blocks/Bytes????? = 1 / 8192

Expired Blocks/Bytes?? = 14 / 114688

Unexpired Blocks/Bytes = 0 / 0

===========================================================================

NON Data Blocks/Bytes? = 47 / 385024

--session 2:還是能讀到修改前的鏡像,因為被刪除的行所對應的block只是被標記為了空閑塊的屬性,block里的內容尚未被清理或者覆蓋,所以session 2能夠實現read consistency

Set transaction read only

Select * from tlobnone where id=1;

ID

----------

NONECOL2

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

1

A

--執行下列語句15次,用盡14個expired

blocks

insert into tlobnone values(1,'B');

--再回到session 2執行時報了ORA-01555,因為數據塊被真正覆蓋了

select * from tlobnone;

*

ERROR:

ORA-01555: snapshot too old: rollback

segment number? with name ""

too small

ORA-22924: snapshot too old

結論6:retention none的情況下無法實現read

consistency,隨時會導致ORA-01555

總結

以上是生活随笔為你收集整理的oracle t44,SecureFiles LOBs基础知识之存储篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。