SecureFiles LOBs基础知识之存储篇
转发自:http://blog.itpub.net/53956/viewspace-1299822/
作者:oliseh 时间:2014-10-15 17:39:26
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 02 00 00 00 01 00 04 29 37 3d a5 00 11 40 90 00
0b 20 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 120ksegment 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 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
。。。。。。此处略去,一共有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。看下面的图就很清楚了。
--创建测试表,disable storage in row
--为了能占用较多的chunk,采用loadclobfromfile将文本文件内容导入的方式,impmd.log.load.lob文件大小为1571061字节,使用存储过程进行导入
v_bfile bfile:=bfilename('HISDMP','impmd.log.load.lob');
dbms_lob.createtemporary(v_clob,FALSE,dbms_lob.session);
insert into tout_lob values(i,v_clob);
select * from v$diag_info where name='Default Trace File'; --shzw1_ora_53936650.trc
alter system flush buffer_cache;
---------- ---------- ---------- ----------
select id,dbms_lob.getlength(outcol2) from tout_lob;
ID DBMS_LOB.GETLENGTH(OUTCOL2)
---------- ---------------------------
alter system dump datafile 115 block 441493;
--shzw1_ora_53936650.trc dump内容,其中03 80 02 a1记录的是包含chunk地址列表的dba地址
tl: 43 fb: --H-FL-- lb: 0x1 cc: 2
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
LobID: 00.00.00.01.00.04.28.c9.b8.ed
select name,file#,rfile# from v$datafile where rfile#=14;
---------------------------------------- ---------- ----------
/oradata02/undo/undo202.dbf 14 14
/oradata06/lobtest_out.dbf 1037 14
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内容节选
0x01 0x0405.018.00165fd5 0x0105a321.128c.10 ---- 1 fsc 0x0000.00000000
flg0 0x18 [ver=0 typ=lhb lock=y]
flg2 0x00 [ver=0 lid=short-rowid hash=n it=n bt=n xfm=n ovr=n aux=n]
hash 0000000000000000000000000000000000000000
--dump一下0x038000a7的内容,包含的就是impmd.log.load.lob文件开头的4030个字符
alter system dump datafile 1037 block 167; --shzw1_ora_54067770.trc
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
--新建测试表,准备好大小为82957 bytes的文本文件 impmd.log.load.12c1
--执行存储过程用impmd.log.load.12c1文件填充lob字段
v_bfile bfile:=bfilename('HISDMP','impmd.log.load.12c1');
dbms_lob.createtemporary(v_clob,FALSE,dbms_lob.session);
insert into tout_lob values(i,v_clob);
select * from v$diag_info where name='Default Trace File'; --shzw1_ora_11994174.trc
alter system flush buffer_cache;
---------- ---------- ---------- ----------
alter system dump datafile 441 block 17562;
tl: 70 fb: --H-FL-- lb: 0x1 cc: 2
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)
---------- ---------------------------
--下面的过程执行6次,每次执行后都dump一下观察是否转为了间接寻址
v_buffer varchar2(6000):=lpad('AB',4000,'AB');
select outcol2 into v_clob from tout_lob for update;
dbms_lob.writeappend(v_clob,4000,v_buffer);
--最新一次执行后的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;
tl: 76 fb: --H-FL-- lb: 0x1 cc: 2
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 bd 03 01 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的结果里终于呈现出间接寻址的迹象了
v_buffer varchar2(6000):=lpad('AB',4000,'AB');
select outcol2 into v_clob from tout_lob for update;
dbms_lob.writeappend(v_clob,4000,v_buffer);
--block 441/17562 dump结果,明显可以看出地址变短了,原来存放的6个chunk address变成了0x038000e1这一个地址
tl: 43 fb: --H-FL-- lb: 0x2 cc: 2
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
LobID: 00.00.00.01.00.04.28.ca.e5.51
-- dba:0x038000e1的dump结果显示该块中包含了前面直接寻址时的chunk地址,
seg/obj: 0x51a69a csc: 0xb89.32fe6c01 itc: 1 flg: E typ: 5 - LOCAL LOBS
fsl: 0 fnx: 0xffffffff ver: 0x01
0x01 0x03fb.012.001414b3 0x030693ac.fae5.07 ---- 1 fsc 0x0000.00000000
flg0 0x18 [ver=0 typ=lhb lock=y]
flg2 0x00 [ver=0 lid=short-rowid hash=n it=n bt=n xfm=n ovr=n aux=n]
hash 0000000000000000000000000000000000000000
但dba:0x038000e1这个起到地址索引效果的块位于lob segment里,并不在lob index里,oracle何时会使用lob index有待进一步考证
结论3:当表里直接寻址的chunk Address地址数大于6个时,会转换为间接寻址的模式
? SecureFiles LOBs的read consistency特性
MAX:在lob segment达到最大值之后,才开始覆盖before-image所占用的block,前提是在建lob segment时必须指定maxsize;
MIN:数据库工作在闪回模式下,限定特定的lob segment能够闪回到多久时间以前的状态
AUTO:before-image的保留时间参照数据库的undo_retention参数
NONE:不保存before-image,用于不需要读一致性的环境
Segment Blocks/Bytes = 64 / 524288
Unused Blocks/Bytes = 34 / 278528
Expired Blocks/Bytes = 13 / 106496
Unexpired Blocks/Bytes = 9 / 73728
==========================================================================
NON Data Blocks/Bytes = 56 / 458752
它将数据块分为unused、used、expired、unexpired四种,
Expired block:空闲的数据库块(包括从未被使用的和曾经被使用过但按照现有的retention策略可以被覆盖使用的)
Unexpired blocks:存放修改前镜像,为满足读一致性需要暂时保留不能被覆盖的数据块
以上输出中的NON Data Blocks是将segment_blocks-used_blocks而得到
###先测试一下在没有达到maxsize的情况下,修改前镜像会一直保留着
v_str:=lpad(chr(i),6000,chr(i));
insert into tlob44 values(j,v_str);
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
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不会被重用
v_str:=lpad(chr(i),6000,chr(i));
insert into tlob44 values(j,v_str);
---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的情况下,如果有新进数据会覆盖修改前镜像
--插入44行记录,都是大小写英文字母,每行6000个字符,占据2个blocks
v_str:=lpad(chr(i),6000,chr(i));
insert into tlob33 values(j,v_str);
v_str:=lpad(chr(i),6000,chr(i));
insert into tlob33 values(j,v_str);
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设置生效
v_str45 varchar2(3000):=lpad('S',3000,'S');
insert into tlob33 values(45,v_str45);
PL/SQL procedure successfully completed.
v_str46 varchar2(3000):=lpad('T',3000,'T');
insert into tlob33 values(46,v_str46);
ORA-60010: adding (144) blocks to LOB segment SCOTT.TLOB_33 with MAXSIZE (128)
--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
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 38 / 311296
select bytes,segment_name from dba_segments where segment_name='TLOB_33';
---------- --------------------
exec check_space_securefile('SCOTT','TLOB_33');
Segment Blocks/Bytes = 128 / 1048576
Unused Blocks/Bytes = 38 / 311296
Used Blocks/Bytes = 89 / 729088
Unexpired Blocks/Bytes = 1 / 8192
select id,dbms_lob.getlength(t33col2) from tlob33 where id=45;
ID DBMS_LOB.GETLENGTH(T33COL2)
---------- ---------------------------
--往tlob33表中再次插入一条记录,unexpired的block会被重用
v_str47 varchar2(3000):=lpad('U',3000,'U');
insert into tlob33 values(47,v_str47);
--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
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 38 / 311296
--session 2,再次查询tlob33收到ORA-1555错误:
select * from tlob33 where id=45;
ORA-01555: snapshot too old: rollback segment number with name "" too small
select count(*) from tlob33 where id<45;
exec check_space_securefile('SCOTT','TLOB_33');
Segment Blocks/Bytes = 128 / 1048576
Unused Blocks/Bytes = 38 / 311296
Used Blocks/Bytes = 86 / 704512
Unexpired Blocks/Bytes = 4 / 32768
===========================================================================
NON Data Blocks/Bytes = 42 / 344064
select count(*) from tlob33 where id<3;
--往tlob33表中再次插入一条记录,4个expired blocks里有两个会被重用,根据先进先出的原则被重用的应该是先插入的id=1的记录所在的block被覆盖
v_str48 varchar2(6000):=lpad('V',6000,'V');
insert into tlob33 values(48,v_str48);
--session 2,测试结果验证了上面的结论:id=1的记录不能读取,id=2的记录能读到
SQL>select count(*) from tlob33 where id<3;
ORA-01555: snapshot too old: rollback segment number with name "" too small
SQL> select * from tlob33 where id=1;
ORA-01555: snapshot too old: rollback segment number with name "" too small
SQL> select * from tlob33 where id=2;
--------------------------------------------------------------------------------
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
--设置undo_retention=90,retention auto时会参照undo_retention设置时间保留修改前镜像
alter system set undo_retention=90;
SQL> show parameter undo_retention
------------------------------------ ----------- ------------------------------
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
Expired Blocks/Bytes = 5 / 40960
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 16 / 131072
v_str_length integer:=50; --指定随机字串的单位长度
v_conn_num integer:=1; --指定随机字串的单元数
v_str:=dbms_random.string('U',v_str_length);
v_str:=v_str||dbms_random.string('U',v_str_length);
dbms_output.put_line(length(v_str));
insert into tlobauto values(i,v_str);
--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
--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的设置,但这也不是绝对的,比如下面的场景
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
Expired Blocks/Bytes = 5 / 40960
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 16 / 131072
Alter system set undo_retention=7200 scope=memory;
SQL> show parameter undo_retention
------------------------------------ ----------- ------------------------------
v_str_length integer:=50; --指定随机字串的单位长度
v_conn_num integer:=1; --指定随机字串的单元数
v_str:=dbms_random.string('U',v_str_length);
v_str:=v_str||dbms_random.string('U',v_str_length);
dbms_output.put_line(length(v_str));
insert into tlobauto values(i,v_str);
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
delete tlobauto where id>6 and id<16;
exec check_space_securefile('SCOTT','TLOB_AUTO');
Segment Blocks/Bytes = 64 / 524288
Unused Blocks/Bytes = 34 / 278528
Expired Blocks/Bytes = 13 / 106496
Unexpired Blocks/Bytes = 9 / 73728
===========================================================================
NON Data Blocks/Bytes = 56 / 458752
--第二轮继续填充tlobauto表,插入11行,每行50个字符
v_str_length integer:=50; --指定随机字串的单位长度
v_conn_num integer:=1; --指定随机字串的单元数
v_str:=dbms_random.string('U',v_str_length);
v_str:=v_str||dbms_random.string('U',v_str_length);
dbms_output.put_line(length(v_str));
insert into tlobauto values(i,v_str);
--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
v_str_length integer:=50; --指定随机字串的单位长度
v_conn_num integer:=1; --指定随机字串的单元数
v_str:=dbms_random.string('U',v_str_length);
v_str:=v_str||dbms_random.string('U',v_str_length);
dbms_output.put_line(length(v_str));
insert into tlobauto values(i,v_str);
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错误
--retention none比较好理解就是永远不保存修改前的镜像,这种情况下无法实现read consistency
insert into tlobnone values(1,'A');
exec check_space_securefile('SCOTT','TLOB_NONE');
Segment Blocks/Bytes = 48 / 393216
Unused Blocks/Bytes = 33 / 270336
Expired Blocks/Bytes = 13 / 106496
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 46 / 376832
Select * from tlobnone where id=1;
--------------------------------------------------------------------------------
--unexpired blocks为0,被删除的数据对应的block直接归到了空闲的block里
SQL> exec check_space_securefile('SCOTT','TLOB_NONE');
Segment Blocks/Bytes = 48 / 393216
Unused Blocks/Bytes = 33 / 270336
Expired Blocks/Bytes = 14 / 114688
Unexpired Blocks/Bytes = 0 / 0
===========================================================================
NON Data Blocks/Bytes = 47 / 385024
Select * from tlobnone where id=1;
--------------------------------------------------------------------------------
--执行下列语句15次,用尽14个expired blocks
insert into tlobnone values(1,'B');
--再回到session 2执行时报了ORA-01555,因为数据块被真正覆盖了
ORA-01555: snapshot too old: rollback segment number with name "" too small
结论6:retention none的情况下无法实现read consistency,随时会导致ORA-01555
SecureFiles LOBs基础知识之存储篇相关推荐
- oracle t44,SecureFiles LOBs基础知识之存储篇
SecureFiles LOBs相比于BasicFiles LOBs具有加密(encryption).去重(deduplicaiton).压缩(compression)等新功能,pctversion, ...
- 计算机数据库管理基本知识,2015年计算机四级考试《数据库技术》基础知识:概念篇...
2015年计算机四级考试<数据库技术>基础知识:概念篇 信息与数据 1. 信息.物质.能量是组成客观世界并促进社会发展的三大基本要素; 2. 信息(Information)--是客观世界事 ...
- datagrid出现相同两组数据_stata 数据操作基础知识:以一篇论文数据操作为例
stata 数据操作基础知识:以一篇论文数据操作为例 上节回顾及问题 统计学学习大图景 数据描述 分位数回归 存在的问题: 1.学了就要多使用,哪怕生搬硬套也要多用 2.时间序列的方法,大家可以操作, ...
- 转发 微博 Qzone 微信 基础知识|存储相关的名词
基础知识|存储相关的名词 静静呐呐呐 2020-09-23 16:10:04 存储 狭义的存储定义是指具体的某种设备,如以前软盘.CD以及硬盘等.广义上的存储是指存储设备,包括硬件存储系统.软件系统. ...
- 反相畴的基础知识和一篇论文
校历第十三周计划(11.18-11.24):反相畴的基础知识和一篇论文 上周由于需要尽快和学长交流,因此提前先看了两篇关于反相畴的论文.由于基础知识的匮乏,这周打算补充一些基础知识,主要来源于薄膜生长 ...
- 计算机等级考试上网怎么做,计算机基础知识上网设置篇
计算机基础知识上网设置篇 分类:计算机等级 | 更新时间:2016-07-08| 来源:转载 现在让我们看看如何进行上网的设置. 首先,让我们查看一下在你的Windows95或是Windows98里是 ...
- 安卓基础知识之Activity篇(一):Activity生命周期
安卓基础知识系列旨在简明扼要地提供面试或工作中常用的基础知识,让对安卓还不太熟悉的小伙伴更快地入门.同时自己在工作中,也没法完全记住所有的基础细节,写这样的系列文章,可以让自己形成一个更完备的知识体系 ...
- Mysql学习总结(4)——MySql基础知识、存储引擎与常用数据类型
1.基础知识 1.1.数据库概述 简单地说:数据库(Database或DB)是存储.管理数据的容器: 严格地说:数据库是"按照某种数据结构对数据进行组织.存储和管理的容器". 总结 ...
- CloudFoundry基础知识之理论篇
本文介绍CF涉及的基础知识,包括CAP理论. CAP理论 任何基于网络的分布式系统,都最多只能拥有以下三条中的两条(三选二): 数据一致性(Consistency),等同于所有节点访问同一份最新的数据 ...
最新文章
- zabbix 监控 elasticsearch
- 什么是分布式事务以及有哪些解决方案?
- [云炬创业基础笔记]第七章创业资源测试1
- vue介绍及环境安装
- php文件上传实验总结,53 PHP文件处理(六)文件上传--总结---细说php
- 为什么DDD是设计微服务的最佳实践
- 第二章:Improving On User Commands--22.显示不同时区的时间
- mysql5.7 json特性_【Mysql】Mysql5.7新特性之-json存储
- linux centos git 自动更新,在centos上搭建git服务器并自动同步代码
- 软件外包,IT咨询和转型
- 【MATLAB深度学习工具箱】学习笔记--螃蟹公母分类Crab Classification
- 电脑录屏用什么软件?录屏软件哪个好用?
- hg8546m虚拟服务器,华为HG8546路由及WIFI配置说明
- element UI指定下拉框样式修改
- Struts1与Struts2的区别和对比(深度好文)
- ibm虚拟化 用的服务器品牌,浅析IBM i虚拟化技术
- memcmp的用法 详讲
- 如何查看docker的版本号是多少
- 欧洲为何没有牛逼的互联网公司
- 【源码】Simscape教程的模拟练习题
热门文章
- 如何让ie的session不共享,如每打开一个新ie窗体都是单独的session,用于单计算机登陆不用账号
- 高效能人士的七个习惯读后感与总结概括-(第十章,)
- linux 终端 浏览器_如何使用W3M从Linux终端浏览
- 极速围观,AI奇艺是如何出卖百度的!官方自己出的工具高速下载百度网盘文件。
- GB2312、GBK、BIG5、Unicode及字符编码基础知识
- 提取桌面壁纸 android,怎么提取android主题包的壁纸
- OSI七层模型英汉名称
- 未来计算机硬件发展趋势是什么,计算机硬件的未来发展趋势是什么?
- Mysql学习——行与列的多种转换
- 荣耀magicbook14 2022 锐龙版 改win10后没有wifi