重庆思庄Oracle、Redhat认证学习论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 2967|回复: 0
打印 上一主题 下一主题

[转载] 关于SecureFile LOB

[复制链接]
跳转到指定楼层
楼主
发表于 2017-1-6 20:09:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.       SecureFile LOB的特点

最近张乐亦(Kamus)在gtalk上问了俺一个问题,为啥SecureFile类型的LOB要比以前的LOB性能要好很多,是不是存储结构上发生了什么变化。这两天抽空看了些资料,现在整理出来算是回答他的问题了。

关于11g以前的LOB类型的实现方式可以参考前一段写的一篇博文《CLOB的物理存储结构及语言编码详解》。从11g开始,Oracle提供了一种新的LOB存储方式叫SecureFile,以前旧有的LOB存储方式就叫BasicFile了。Oracle宣称,“SecureFile不仅是新一代 LOB,它们还为 LOB 带来了更多的价值,尤其是以前只能在文件系统领域中获得的特性。SecureFile可以进行加密以确保安全性,可以进行重复消除和压缩以提高存储效率,可以进行缓存(或不进行缓存)以加快访问(或节省缓冲池空间),可以按多个级别记录以减少崩溃后的平均恢复时间。引入 SecureFile 后,您可以在数据库中存储更多的非结构化文档,而不会导致过多的开销,也不会失去 OS 文件系统提供的任何重要功能。”

简单来说就三条:

一、提供了压缩、重复消除、加密等新功能

二、比以前的LOB的性能提高很多

三、易用性(无需设置CHUNK、PCTVERSION、FREELISTS、FREELIST GROUPS、FREEPOOLS参数)

注意:压缩需要Oracle Advanced Compression Option,加密需要Oracle Advanced Security Option,这两个option都是单独购买的,没有包括在Enterprise Edition里面。
2.       使用SecureFile

想要使用SecureFile LOB很简单,只需指定STORE AS SECUREFILE子句就行了(测试环境为11gR2):

CREATE TABLE tst.t11 (id number,c1 CLOB) LOB (c1) STORE AS SECUREFILE;

Securefile列标明了是否为SecureFile类型的LOB:

SELECT table_name,segment_name,index_name,securefile FROM dba_lobs WHERE table_name='T11';
TABLE_NAME SEGMENT_NAME                   INDEX_NAME                     SECUREFIL
---------- ------------------------------ ------------------------------ ---------
T11        SYS_LOB0000069030C00001$$      SYS_IL0000069030C00001$$       YES

使用Securefile LOB的表也是自动生成LOB segment和LOB index的。但是此时LOB index只有在使用重复消除功能时才会使用,在其他情况下均不会使用。要注意,Securefile LOB只能在ASSM的表空间(自动管理的表空间)里创建,不过既然从9i起ASSM表空间就是默认设置了,一般这里不会有多大问题。还要多说一句,只是要求SecureLOB所在的LOB列数据需要存放在ASSM表空间中,而包含LOB列的那个表,你还是可以放在手动管理的表空间中。

想使用SecureFile LOB,对数据库的参数DB_SECUREFILE设置也有一定的要求:

PERMITTED:数据库的默认参数。指定SecureFile时创建SecureFile类型的LOB;未指定时,或显式指定BasicFile时,创建BasicFile类型的LOB。

FORCE:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,无论STORAGE子句是否指定SecureFile,均报ORA-43853错。

ALWAYS:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,若 STORAGE子句未显式指定LOB类型,创建为BasicFile类型的LOB;若STORAGE子句显式指定SecureFile类型,则也报 ORA-43853错。

NEVER:无论是否指定SecureFile,强制创建BasicFile类型的LOB。指定SecureFile类型特有的功能如压缩,加密,重复消除时,报ORA-43854错。

IGNORE:无论是否指定SecureFile,强制创建BasicFile类型的LOB。忽略SecureFile类型特有的功能,创建BasicFile类型的LOB。
3.       BasicFile和SecureFile的架构比较
3.1.     可变Chunk

首先介绍一下SecureFile中的可变Chunk。大家都知道在BasicFile的LOB中,Chunk的大小是一定的,最小跟DB Block的大小一样,最大为32KB,这存在一些问题。比如chunk比LOB的数据小很多的情况下,访问LOB就会产生很多IO,而chunk比 LOB的数据大很多的情况下,又会产生对存储空间的浪费。而在SecureFile中,chunk的size是可变的,由Oracle自动动态分配,最小跟DB Block的大小一样,最大为64MB。这样在存储较小的LOB时,使用比较小的chunk;在存储比较大的LOB时,会使用比较大的chunk。注意不是说一个LOB就放在一个chunk里,而是oracle根据LOB data的数据大小会自动决定chunk数和chunk的size,具体可以看下面“SecureFile的物理存储结构”一节的实验结果。
3.2.     LOB index

在LOB数据的存储方式上,两种LOB也有很大的区别。关于BasicFile的存储方式,在《CLOB的物理存储结构及语言编码详解》一文中有详细的介绍,大概就是表中的LOB字段只存储LOB locator,指向LOB index,LOB index再指向LOB segment里实际的LOB数据。不难看出,这里增加了一个LOB index的结构,那么不可避免的,LOB index就有可能产生竞争,成为瓶颈。在SecureFile中,LOB index只有在使用重复消除功能时才会使用(关于这个结论的验证方法,在CLOB那篇文章中有记载,这里不再赘述了)。简而言之,SecureFile中只要不使用重复消除功能就没LOB index什么事,自然性能就上去了。
BasicFile         Col1         LOB col         —->         LOB index         —->         LOB data
SecureFile         Col1         LOB col         —————->         LOB data
3.3.     空闲空间搜索

在BasicFile里,关于有空间的使用情况的信息是保存在LOB index和LOB segment里的。在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

1. 在LOG segment的管理区搜索空闲空间,如果没有,转下一步

2. 访问LOB index,把可以释放的空间(如已经commit的transaction使用的UNDO)释放掉,并更新索引entry。如果不存在这种可以释放的空间,转下一步

3. 将HWM升高,扩大LOB segment,使用新分配的空间

由此可见,BasicFile的LOB在搜索空闲空间时,可能会去扫描LOB index。因此LOB index的竞争,或者在LOB数据很多的情况下,搜索LOB index的空闲空间这个操作本身都会造成时间上的花费。

对于空闲空间的管理,SecureFile将其放入了shared pool,这比BasicFile空闲空篇博文《CLOB的物理存储结构及语言编码详解》。从11g开始,Oracle提供了一种新的LOB存储方式叫SecureFile,以前旧有的LOB存储方式就叫BasicFile了。Oracle宣称,“SecureFile不仅是新一代 LOB,它们还为 LOB 带来了更多的价值,尤其是以前只能在文件系统领域中获得的特性。SecureFile可以进行加密以确保安全性,可以进行重复消除和压缩以提高存储效率,可以进行缓存(或不进行缓存)以加快访问(或节省缓冲池空间),可以按多个级别记录以减少崩溃后的平均恢复时间。引入 SecureFile 后,您可以在数据库中存储更多的非结构化文档,而不会导致过多的开销,也不会失去 OS 文件系统提供的任何重要功能。”

简单来说就三条:

一、提供了压缩、重复消除、加密等新功能

二、比以前的LOB的性能提高很多

三、易用性(无需设置CHUNK、PCTVERSION、FREELISTS、FREELIST GROUPS、FREEPOOLS参数)

注意:压缩需要Oracle Advanced Compression Option,加密需要Oracle Advanced Security Option,这两个option都是单独购买的,没有包括在Enterprise Edition里面。
2.       使用SecureFile

想要使用SecureFile LOB很简单,只需指定STORE AS SECUREFILE子句就行了(测试环境为11gR2):

CREATE TABLE tst.t11 (id number,c1 CLOB) LOB (c1) STORE AS SECUREFILE;

Securefile列标明了是否为SecureFile类型的LOB:

SELECT table_name,segment_name,index_name,securefile FROM dba_lobs WHERE table_name='T11';
TABLE_NAME SEGMENT_NAME                   INDEX_NAME                     SECUREFIL
---------- ------------------------------ ------------------------------ ---------
T11        SYS_LOB0000069030C00001$$      SYS_IL0000069030C00001$$       YES

使用Securefile LOB的表也是自动生成LOB segment和LOB index的。但是此时LOB index只有在使用重复消除功能时才会使用,在其他情况下均不会使用。要注意,Securefile LOB只能在ASSM的表空间(自动管理的表空间)里创建,不过既然从9i起ASSM表空间就是默认设置了,一般这里不会有多大问题。还要多说一句,只是要求SecureLOB所在的LOB列数据需要存放在ASSM表空间中,而包含LOB列的那个表,你还是可以放在手动管理的表空间中。

想使用SecureFile LOB,对数据库的参数DB_SECUREFILE设置也有一定的要求:

PERMITTED:数据库的默认参数。指定SecureFile时创建SecureFile类型的LOB;未指定时,或显式指定BasicFile时,创建BasicFile类型的LOB。

FORCE:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,无论STORAGE子句是否指定SecureFile,均报ORA-43853错。

ALWAYS:无论是否指定SecureFile,强制创建SecureFile类型的LOB。在手动管理的表空间上创建LOB时,若 STORAGE子句未显式指定LOB类型,创建为BasicFile类型的LOB;若STORAGE子句显式指定SecureFile类型,则也报 ORA-43853错。

NEVER:无论是否指定SecureFile,强制创建BasicFile类型的LOB。指定SecureFile类型特有的功能如压缩,加密,重复消除时,报ORA-43854错。

IGNORE:无论是否指定SecureFile,强制创建BasicFile类型的LOB。忽略SecureFile类型特有的功能,创建BasicFile类型的LOB。
3.       BasicFile和SecureFile的架构比较
3.1.     可变Chunk

首先介绍一下SecureFile中的可变Chunk。大家都知道在BasicFile的LOB中,Chunk的大小是一定的,最小跟DB Block的大小一样,最大为32KB,这存在一些问题。比如chunk比LOB的数据小很多的情况下,访问LOB就会产生很多IO,而chunk比 LOB的数据大很多的情况下,又会产生对存储空间的浪费。而在SecureFile中,chunk的size是可变的,由Oracle自动动态分配,最小跟DB Block的大小一样,最大为64MB。这样在存储较小的LOB时,使用比较小的chunk;在存储比较大的LOB时,会使用比较大的chunk。注意不是说一个LOB就放在一个chunk里,而是oracle根据LOB data的数据大小会自动决定chunk数和chunk的size,具体可以看下面“SecureFile的物理存储结构”一节的实验结果。
3.2.     LOB index

在LOB数据的存储方式上,两种LOB也有很大的区别。关于BasicFile的存储方式,在《CLOB的物理存储结构及语言编码详解》一文中有详细的介绍,大概就是表中的LOB字段只存储LOB locator,指向LOB index,LOB index再指向LOB segment里实际的LOB数据。不难看出,这里增加了一个LOB index的结构,那么不可避免的,LOB index就有可能产生竞争,成为瓶颈。在SecureFile中,LOB index只有在使用重复消除功能时才会使用(关于这个结论的验证方法,在CLOB那篇文章中有记载,这里不再赘述了)。简而言之,SecureFile中只要不使用重复消除功能就没LOB index什么事,自然性能就上去了。
BasicFile         Col1         LOB col         —->         LOB index         —->         LOB data
SecureFile         Col1         LOB col         —————->         LOB data
3.3.     空闲空间搜索

在BasicFile里,关于有空间的使用情况的信息是保存在LOB index和LOB segment里的。在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

1. 在LOG segment的管理区搜索空闲空间,如果没有,转下一步

2. 访问LOB index,把可以释放的空间(如已经commit的transaction使用的UNDO)释放掉,并更新索引entry。如果不存在这种可以释放的空间,转下一步

3. 将HWM升高,扩大LOB segment,使用新分配的空间

由此可见,BasicFile的LOB在搜索空闲空间时,可能会去扫描LOB index。因此LOB index的竞争,或者在LOB数据很多的情况下,搜索LOB index的空闲空间这个操作本身都会造成时间上的花费。

对于空闲空间的管理,SecureFile将其放入了shared pool,这比BasicFile空闲空间管理的效率有了质的提高。 Shared Pool里的这个内存结构叫In-memory dispenser,它把空闲空间的信息cache在内存里,因此速度要比访问LOB index快了N个数量级。In-memory dispenser负责接受前台进程对于LOB空间的请求,并进行chunk的分配。

在In-memory dispenser中管理的空闲空间不是全部,而只是一部分而已,它的信息由后台进程SMCO/Wnnn来定期的更新。SMCO/Wnnn监视 SecureFile LOB segment的使用情况,根据需要保证空闲空间的供应。注意SMCO/Wnnn也负责普通的ASSM表空间的空间动态分配。

1. SMCO进程(Space Management Coordinator)。负责前瞻式(Proactive)的空间分配,它动态产生slave进程Wnnn来完成实际的工作。

2. Wnnn(SMCO Worker)每10分钟扫描一遍LOB segment的状态,根据需要把空chunk移动到In-memory dispenser中。如果这样空chunk还是不够,则扩大LOB segment。

此时在INSERT或UPDATE操作LOB segment时,以下面的顺序来搜索空闲空间:

1. 前台进程向In-memory dispenser发出需要chunk的请求

2. In-memory dispenser里的chunk信息里如果空chunk数量不足,或者空chunk的size不够时,在LOG segment的管理区搜索空闲空间,将空chunk的信息cache在In-memory dispenser里。如果搜索不到空闲空间,转下一步

3. 将HWM升高,扩大LOB segment,使用新分配的空间
3.4.     STORAGE参数

跟BasicFile一样,SecureFile同样也有enable storage in row和disable storage in row的区别,在SecureFile的LOB里默认设置同样也是enable storage in row。LOB控制结构size加上LOB数据size一共未满4000字节时,enable storage in row的情况下就存储在源表的LOB列内,超出时就存放在LOB segment里;而disable storage in row的情况下则无论是否超过4000字节,LOB数据均存放在LOB segment里。

《CLOB的物理存储结构及语言编码详解》一文中提到过,enable storage in row的情况下源表的LOB列最多能存放3964字节;而在DB11gR1的SecureFile LOB中,变成了3740字节;DB11gR2时又变成了3952字节。均为引用的数据,具体区别尚未弄清。个人认为Size的变化都是因为LOB的控制信息发生了细微的变化。注意这里的size都是在未使用重复消除、加密、压缩选项的情况下得出的。
4.       SecureFile的物理存储结构

下面就是本文的重头戏了,SecureFile的LOB到底在物理上是怎么存储的。在Table的Segment里的LOB列中,存放着两个 layer:Locator Layer(20字节)和Inode Layer。Locator的内容和BasicFile里是一样的,也包括了控制信息和10字节的LOB ID。而Inode Layer包含了RCI Header和Inode部分,其中Inode部分包含了指向LOB segment的指针,或者在In-line存储的情况下包含实际的LOB 数据。RCI(LOB Row-Column Intersection)即表Segment里存储的LOB列的所有数据,RCI Header里存储的是SecureFile的LOB控制信息。具体的定义如下:

2字节的Inode Layer整个的size,即表Segment里LOB列中,Locator Layer之外的size。如果是in-line存储的话也包括LOB数据的size在内。

1字节的flag,具体含义如下

0×01 此LOB是有效LOB

0×02 此inode在Index中

0×04此inode是in-line的

0×08 in-line的数据是实际的LOB数据

0×10 此inode是临时lob的控制结构

0×40此LOB是SecureFile的LOB

比如我们dump出block这里是0×48,就说明这个LOB是SecureFile的LOB,而且是in-line存储的。

1字节的SecureFile的LOB的选项flag:0×1是启用重复消除,0×2是启用压缩,0×4是启用加密。下面举例说明:

上文里创建过T11表,T11表没指定storage in row选项,因此就是默认的enable storage in row。给T11表插入两条测试数据,一条是in-line方式存储的,一条是out-of-line方式存储的:

SELECT id,dbms_lob.getlength(c1) FROM tst.t11;
ID DBMS_LOB.GETLENGTH(C1)
---------- ----------------------
1                     56
2                  25583
ALTER databas FLUSH buffer_cache;
SELECT dbms_rowid.rowid_to_absolute_fno(rowid,'TST','T11') fno,
dbms_rowid.rowid_block_number(rowid) bno,id FROM tst.t11;
FNO        BNO         ID
---------- ---------- ----------
5        132          1
5        132          2
ALTER system dump datafile 5 block 132;
SELECT value FROM v$diag_info WHERE name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/dbeuc/dbeuc/trace/dbeuc_ora_25611.trc

先看第一条数据:

tab 0, row 0, @0x1f03
tl: 149 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02
col  1: [142]
00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00 00 00 61 3c c7 00 7a 48 90 00
< - - - - - - A - - - - - - -> <- - - - - - B - - - - - - -> <- - C - -> <-   74 00 00 70 01 30 d3 30 b8 30 cd 30 b9 90 4b 55 b6 30 4c … … …  - - - D - - -> < - - - - - - - - - - E - - - - - - - - - … … …
LOB
Locator:
   Length:        84(142)
   Version:        1
   Byte Length:    2
   LobID: 00.00.00.01.00.00.00.61.3c.c7
   Flags[ 0x02 0x0c 0x80 0x80 ]:
     Type: CLOB
     Storage: SecureFile
     Characterset Format: IMPLICIT
     Partitioned Table: No
     Options: VaringWidthReadWrite
   SecureFile Header:
     Length:   122
     Old Flag: 0x48 [ DataInRow SecureFile ]
     Flag 0:   0x90 [ INODE Valid ]
     Layers:
       Lengths Array: INODE:116
       INODE:
         00 00 70 01 30 d3 30 b8 30 cd 30 b9 90 4b 55 b6 30 4c 30 88
         … … …

上面dump出的十六进制信息含义如下:

A:00 54 00 01 02 0c 80 80 00 02     Lob Locator Header

我认为这里的定义应该跟BasicFile没有发生变化:2字节的LOB locator长度  (除这两个长度字节外)+ 2字节的LOB locator structure版本 + 4字节的FLAG + 2字节的字符集里字符的长度

B:00 00 00 01 00 00 00 61 3c c7     LOB ID

C:00 7a 48 90      RCI Header

0x007a(=122字节):这个filed后的Inode的size(即D部分 + E部分的size)

0×48:这是in-line的SECUREFILE LOB

0×90:未启用重复消除,压缩,加密

D:00 74 00 00 70 01    Inode管理信息

0×0074(=116字节):这个field后面(即后面的00 00 70 01四个字节 + E部分)Inode数据的size。116减4字节为112字节,这跟上面得到的LOB的length为56是能匹配上的。

0×0000:in-line存储LOB data。第二位的0表示后面LOB Data的size是用1字节表示

0×70(=112字节):LOB Data的size

0×01:LOB Data的version

E:这里开始是真正的LOB Data

第二条:

tab 0, row 1, @0x1893
tl: 51 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 03
col  1: [44]
00 54 00 01 02 0c 80 80 00 02 00 00 00 01 00 00 00 61 3d 2e 00 18 40 90 00
< - - - - - - A - - - - - - -> <- - - - - - B - - - - - - -> <- - C - -> <-   12 21 00 c7 de 0a 01 01 01 40 33 a2 01 01 01 40 33 14 06  - - - - D - - - - -> <- - - - - - - - E - - - - - - - ->
LOB
Locator:
   Length:        84(44)
   Version:        1
   Byte Length:    2
   LobID: 00.00.00.01.00.00.00.61.3d.2e
   Flags[ 0x02 0x0c 0x80 0x80 ]:
     Type: CLOB
     Storage: SecureFile
     Characterset Format: IMPLICIT
     Partitioned Table: No
     Options: VaringWidthReadWrite
   SecureFile Header:
     Length:   24
     Old Flag: 0x40 [ SecureFile ]
     Flag 0:   0x90 [ INODE Valid ]
     Layers:
       Lengths Array: INODE:18
       INODE:
         21 00 c7 de 0a 01 01 01 40 33 a2 01 01 01 40 33 14 06

上面dump出的十六进制信息含义如下:

A:Lob Locator Header

B:LOB ID

C:00 18 40 90   RCI Header

0×0018(=24字节):这个filed后的Inode的size(即D部分 + E部分的size)

0×40:这是out-line的SECUREFILE LOB

0×90:未启用重复消除,压缩,加密

D:00 12 21 00 c7 de 0a 01    Inode管理信息

0×0012(=18字节):这个field后面(即后面的六个字节 + E部分)Inode数据的size。

0×2100:第一位的2表示后面的E部分是chunk的RDBA + size,第二位的1表示后面LOB Data的size是用2字节表示

0xc7de(=51166字节):LOB Data的size

0x0a: LOB Data的version

0×01:代表后面有2个chunk,如果是2就是3个chunk,以此类推。

E:01 01 40 33 a2 01 01 01 40 33 14 06

01 01 40 33 a2 01:RDBA以0x014033a2开头的1个block

01 01 40 33 14 06:RDBA以0×01403314开头的6个block

我们看一下第一个chunk:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER('14033a2','xxxxxxxx'))
bno FROM dual;
BNO
----------
13218

得到:

bdba    [0x014033a2]
kdlich  [0x2b4878d45a4c 56]
flg0  0x28 [ver=0 typ=data lock=y]
flg1  0x00
scn   0x0000.0045ff19
lid   00000001000000613d2e   - ->这是LOB ID
rid   0x00000000.0000
kdlidh  [0x2b4878d45a64 24]
flg2  0x00 [ver=0 lid=short-rowid hash=n cmap=n pfill=n]
flg3  0x00
pskip 0
sskip 0
hash  0000000000000000000000000000000000000000
hwm   8060   - ->这个block里存放了8060字节的数据
spr   0
data  [0x2b4878d45a80 52 8060]
30 d3 30 b8 30 cd 30 b9 90 4b 55 b6 30 4c 30 88 30 8a 89 07 96 d1 30 55 30 92

我们再看一下最后一个block:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER('1403314','xxxxxxxx'))
bno FROM dual;
BNO
----------
13076

现在需要dump从13076开始的第6个即13081号block,得到:

… … …
hwm   2806
… … …

一共8060×6+2806=51166字节的LOB data,这与前面的结果是能相互印证的。

下面我们再来看disable storage in row的情况下SecureFile是如何存储的。

在这种情况下指向LOB data的指针可能有两种存储方式:

第一种:LOB data的size不算很大的情况下,在Table Segment里的LOB列中以chunk的初始RDBA + size的方式存储,一个chunk信息接着一个chunk信息;

第二种:LOB data的size很大的情况下,在Table Segment里的LOB列中存储LHB(Lob Header Block)的信息,在LHB中存放所有chunk及size的列表。

第一种跟上面的第二条数据存储方式差不多,就不再介绍了,下面我们看第二种情况:

CREATE TABLE tst.t12 (id number,c2 CLOB) LOB (c2) STORE AS SECUREFILE(disable storage IN row);
插入一条很大的LOB数据:
SELECT id,dbms_lob.getlength(c2) FROM tst.t12;
         ID DBMS_LOB.GETLENGTH(C2)
---------- ----------------------
          1               49498672
ALTER databas FLUSH buffer_cache;
SELECT dbms_rowid.rowid_to_absolute_fno(rowid,'TST','T12') fno,
dbms_rowid.rowid_block_number(rowid) bno,id FROM tst.t12;
        FNO        BNO         ID
---------- ---------- ----------
          5        173          1
ALTER system dump datafile 5 block 173;

现在来看一下Table Segment里存放LOB列的地方是什么信息:

tab 0, row 0, @0x1f1b
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 00 00 61 3e 58 00 11 40 90 00
< - - - - - - A - - - - - - > <- - - - - - B - - - - - - -> <- - C - -> <-   0b 43 00 05 e6 94 60 41 01 40 3b 81  - - - - D - - - - - - > <- - E - ->
LOB
Locator:
   Length:        84(37)
   Version:        1
   Byte Length:    2
   LobID: 00.00.00.01.00.00.00.61.3e.58
   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:
         43 00 05 e6 94 60 41 01 40 3b 81

上面dump出的十六进制信息含义如下:

A:Lob Locator Header。

B:LOB ID

C:00 11 40 90   RCI Header

0×0018(=17字节):这个filed后的Inode的size(即D部分 + E部分的size)

0×40:这是out-line的SECUREFILE LOB

0×90:未启用重复消除,压缩,加密

D:00 0b 43 00 05 e6 94 60 41    Inode管理信息

0x000b(=11字节):这个field后面(即后面的四个字节 + E部分)Inode数据的size。

0×4300:第一位的4表示后面的E部分是LHB的RDBA,第二位的3表示LOB data的size是4字节。

0x05e69460(=98997344字节):LOB Data的size

0×41: LOB Data的version

E:01 40 3b 81 这是LHB的RDBA

我们把LHB给dump出来看看:

SELECT DBMS_UTILITY.data_block_address_block(TO_NUMBER(LTRIM('01403b81'),'xxxxxxxx'))
BNO FROM dual;
BNO
----------
15233
ALTER system dump datafile 5 block 15233;

可以看到下面有chunk列表,以 block数 + RDBA的形式存储:

bdba    [0x01403b81]
kdlich  [0x2b3f1e77844c 56]
   flg0  0x18 [ver=0 typ=lhb lock=y]
   flg1  0x00
   scn   0x0000.00462283
   lid   00000001000000613e58
   rid   0x00000000.0000
kdlihh  [0x2b3f1e778464 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.98997344
   ver   0.65
   #ext  100
   asiz  100
   hwm   100
   ovr   0x00000000.0
   dba0  0x00000000
   dba1  0x00000000
   dba2  0x00000000
   dba3  0x00000000
   auxp  0x00000000
   ldba  0x01406ab5
nblk  12283   - ->这个LOB共占用了多少个block
[0] 0x00 0x00 73 0x014039b7   - ->从RDBA 0x014039b7 开始的73个block
[1] 0x00 0x00 7 0x014000c9   - ->从RDBA 0x014000c9开始的7个block
[2] 0x00 0x00 5 0x014000bb
… … … …
[97] 0x00 0x00 795 0x01406665
[98] 0x00 0x00 224 0x01406585
[99] 0x00 0x00 85 0x01406a61

接下来对于LOB data所在的block的dump这里就不做了,方法跟上述的类似。
5.       两种LOB性能测试比较
上面说了这么多新的SecureFile的LOB怎么怎么好,怎么怎么牛,大家一定有疑问了,是不是我在这忽悠大家呢。下面就给大家看些干货,真实的测试数据。

首先介绍下LOB参数:
LOGGING:在CREATE/UPDATE/INSERT LOB数据时会写入REDO LOG文件。但NOLOGGING会Internally转换成FILESYSTEM_LIKE_LOGGING,而FILESYSTEM_LIKE_LOGGING会确保数据库CRASH完整恢复
NOLOGGING:在CREATE/UPDATE/INSERT LOB数据时不写入REDO LOG文件。
FILESYSTEM_LIKE_LOGGING:数据库只记录LOB的METADATA到REDO LOG
NOCACHE:LOB数据不CACHE在SGA
CACHE:LOB数据CACHE在SGA
测试环境:
虚拟机OEL5.5 64bit + DB11.2.0.1,测试数据是一个110MB的文本文档lob.txt:
[oracle@cdcjp11vm1 ~]$ du -m lob.txt
110     lob.txt
[oracle@cdcjp11vm1 ~]$ cat lob.txt|wc -l
1916928
[oracle@cdcjp11vm1 ~]$ head –n1 lob.txt
ビジネス運営がより複雑さを増すなかで、ITに対する変化の要求は高まりを見せ、関連するリスクの軽減もあわせて求めら

创建了一个存储过程insert_clob(代码在附录中),作用是插入若干条CLOB数据即lob.txt的内容,本次测试每次是插20条数据,共2.2GB,记录所花的时间。
存储方式        DML类型        SecureFile        MB/s        BasicFile        MB/s        性能比%
CACHE + LOGGING        INSERT        54.152 s        40.626        243.726 s        9.027        450.05%
CACHE + NOLOGGING        INSERT        59.398 s        37.038        NOT support        -        -
NOCACHE + LOGGING        INSERT        43.799 s        50.229        289.213 s        7.607        660.23%
NOCACHE + NOLOGGING        INSERT        48.512 s        45.349        293.454 s        7.497        604.90%

结论已经很明显,新SecureFile格式的LOB性能相比较以前BasicFile有了巨大的提升,而且在最典型LOB的选项组合NOCACHE + LOGGING的情况下,性能提升的比例最大。

两种LOB的性能数据也可以参考这篇博文:
http://blog.sina.com.cn/s/blog_6058d7c10100nx26.html
他的测试结果如下,有的测试结果跟我的结果相比有一定的出入,可能是环境的问题,也可能是数据的问题(我是110MB的文本文件,他是5MB的文本文件),也可能是程序的问题(他用的java,我用的是PL/SQL)。另外他这篇文章里有关于SELECT(即READ)的性能数据,在NOCACHE + LOGGING的情况下,性能提升约三倍。
存储方式        DML类型        SecureFile MB/s        BasicFile MB/s        性能比%
CACHE + LOGGING        INSERT        9.17        8.64        106.13%
CACHE + LOGGING        SELECT        39.52        4.42        894.12%
CACHE + NOLOGGING        INSERT        31.56        -        -
CACHE + NOLOGGING        SELECT        35.31        -        -
NOCACHE + LOGGING        INSERT        36.63        2.32        1578.88%
NOCACHE + LOGGING        SELECT        50.28        16.28        308.85%
NOCACHE + NOLOGGING        INSERT        9.38        2.51        373.71%
NOCACHE + NOLOGGING        SELECT        5.54        11.36        48.76%
1.        总结及附录
做个总结吧,我认为SecureFile的LOB之所以比BasicFile的LOB性能有提升,就是因为可变chunk、LOB index不再使用、空闲空间搜索放到了shared pool里这三大原因共同决定的,尤其是后两者,比起以前的BasicFile LOB,架构设计上有了飞跃。我们也能看出虽然Oracle数据库的发展不像以前那么革命性了,但是在很多方面,新版本的Oracle数据库还是取得了巨大的进步。

附录:
测试表(只写了一种,其他的选项组合类似):
create table tst.LOBTAB(ARTICLE_ID NUMBER PRIMARY KEY,ARTICLE_NAME VARCHAR2(50),
ARTICLE_DATA CLOB) tablespace data lob (ARTICLE_DATA)
store as SECUREFILE (tablespace DATA cache) LOGGING;

插入CLOB数据的存储过程insert_clob:
create or replace procedure tst.insert_clob (fromid in number,endid in number)
AS
i NUMBER;
V_LOB CLOB;
V_FILE BFILE := BFILENAME('HOME_DIR', 'lob.txt');
V_SOURCE NUMBER := 1;
V_DEST NUMBER := 1;
V_LANG NUMBER := 0;
V_WARN NUMBER;
BEGIN

for i in fromid..endid loop
V_SOURCE := 1;
V_DEST := 1;
INSERT INTO tst.LOBTAB VALUES (i, 'ABC'||to_char(i), 'TEST');
UPDATE tst.LOBTAB SET ARTICLE_DATA = EMPTY_CLOB where ARTICLE_ID=i RETURN ARTICLE_DATA INTO V_LOB;
DBMS_LOB.FILEOPEN(V_FILE);
DBMS_LOB.OPEN(V_LOB, DBMS_LOB.LOB_READWRITE);

DBMS_LOB.LOADCLOBFROMFILE(
V_LOB,
V_FILE,
DBMS_LOB.GETLENGTH(V_FILE),
V_DEST,
V_SOURCE,
0,
V_LANG,
V_WARN);

DBMS_LOB.CLOSE(V_LOB);
DBMS_LOB.FILECLOSEALL;
COMMIT;
end loop;
END;
/

计算CLOB的INSERT操作的时间差是使用以下的PL/SQL:
declare
a VARCHAR2(50);
b VARCHAR2(50);
begin
select to_char(systimestamp,'HH24:MI:SS.FF3') into a from dual;
TST.insert_clob(1,20);
select to_char(systimestamp,'HH24:MI:SS.FF3') into b from dual;
dbms_output.put_line(a);
dbms_output.put_line(b);
end;
/

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 支持支持 反对反对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|重庆思庄Oracle、Redhat认证学习论坛 ( 渝ICP备12004239号-4 )

GMT+8, 2024-4-27 07:43 , Processed in 0.087600 second(s), 20 queries .

重庆思庄学习中心论坛-重庆思庄科技有限公司论坛

© 2001-2020

快速回复 返回顶部 返回列表