查看: 29183|回复: 31

[原创] 深入SecureFile—新一代LOB揭秘

[复制链接]
论坛徽章:
3
生肖徽章2007版:兔
日期:2009-03-10 21:13:502014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11
跳转到指定楼层
1#
发表于 2011-1-19 14:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 yexichang 于 2014-2-7 11:45 编辑

全文PDF版本可以在这里下载,格式排版要容易看一些
http://wenku.baidu.com/link?url=nb3KDa4Ca0JIc5_zf-mX0krI4VGLiBTPmXCLJT25uDNZCAuZ3wLcQXWetpZq_il8FPAU1nwoCK-DQ5XtqgatZoxKb5q_Mqg_FXXNpvjGFHe

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;
/

[ 本帖最后由 yexichang 于 2011-1-21 17:39 编辑 ]
论坛徽章:
41
马上加薪
日期:2014-02-19 11:55:14铁扇公主
日期:2012-02-21 15:02:402012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-02-13 15:12:092012新春纪念徽章
日期:2012-01-04 11:50:44ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15ITPUB年度最佳BLOG写作奖
日期:2012-03-13 17:09:53
2#
发表于 2011-1-19 15:07 | 只看该作者
Nice Job.

secooler

使用道具 举报

回复
论坛徽章:
47
蒙奇·D·路飞
日期:2017-03-27 08:04:23马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11一汽
日期:2013-09-01 20:46:27复活蛋
日期:2013-03-13 07:55:232013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:03:322012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20
3#
发表于 2011-1-20 06:59 | 只看该作者
本帖最后由 Yong Huang 于 2015-1-26 21:37 编辑

Very well written. Indeed http://www.orafan.net/blog/352.html is more readable. Please remove the duplicate part starting with "这比BasicFile空闲空篇博文".

I have a strong feeling event 45050 is related to what is called in-memory dispensers. The event may flush or dump those dispensers. But it's *very* undocumented and I can't get it to work. More about these dispensers can be found in patent:
http://www.freepatentsonline.com/7664799.html

It's interesting that Oracle calls this technology SecureFiles and SecureFile LOBs. But I bet most users care more about the compression part of the technology than the security part.

Yong Huang


[2015-01-26 Update]

The URL http://www.orafan.net/blog/352.html no longer works. But we can find the archived page at
https://web.archive.org/web/2013 ... n.net/blog/352.html

In case anyone asks me how I find the "very undocumented" event 45050, I remember I found event code AFFA in one of Dennis Yurichev's dumps of certain binaries.

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
4#
发表于 2011-1-20 08:09 | 只看该作者
好文章,学习

使用道具 举报

回复
招聘 : 数据库管理员
论坛徽章:
20
祖国60周年纪念徽章
日期:2009-10-09 08:28:00数据库板块每日发贴之星
日期:2011-02-20 01:01:01ITPUB季度 技术新星
日期:2011-04-02 10:31:09ITPUB十周年纪念徽章
日期:2011-11-01 16:24:042012新春纪念徽章
日期:2012-01-04 11:54:26玉石琵琶
日期:2012-02-21 15:04:38最佳人气徽章
日期:2012-03-13 17:39:18ITPUB 11周年纪念徽章
日期:2012-10-09 18:09:192013年新春福章
日期:2013-02-25 14:51:242011新春纪念徽章
日期:2011-02-18 11:43:33
5#
发表于 2011-1-20 10:39 | 只看该作者
good

使用道具 举报

回复
招聘 : 数据库管理员
论坛徽章:
9
生肖徽章2007版:牛
日期:2009-03-10 21:26:492010新春纪念徽章
日期:2010-01-04 08:33:082010年世界杯参赛球队:葡萄牙
日期:2010-02-22 14:35:242010新春纪念徽章
日期:2010-03-01 11:19:092010广州亚运会纪念徽章:射击
日期:2010-09-08 23:42:12ITPUB9周年纪念徽章
日期:2010-10-08 09:31:212010广州亚运会纪念徽章:拳击
日期:2010-10-30 00:46:582011新春纪念徽章
日期:2011-02-18 11:43:322011新春纪念徽章
日期:2011-03-01 08:49:39
6#
发表于 2011-1-20 11:32 | 只看该作者
我也研究了一下 ,我试了一下压缩+消重竟然占用了更到的空间。

使用道具 举报

回复
论坛徽章:
0
7#
发表于 2011-1-20 11:45 | 只看该作者
好文章,学习

使用道具 举报

回复
论坛徽章:
3
生肖徽章2007版:兔
日期:2009-03-10 21:13:502014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11
8#
 楼主| 发表于 2011-1-20 13:06 | 只看该作者
原帖由 killkill_shadow 于 2011-1-20 11:32 发表
我也研究了一下 ,我试了一下压缩+消重竟然占用了更到的空间。

这主要是依赖于你的数据。
压缩是压缩单条LOB,文本的压缩率高些,估计原理类似winrar之类的压缩
消除重复是多条LOB的内容完全一样的情况下使用,重复的LOB只记录一遍

使用道具 举报

回复
论坛徽章:
3
生肖徽章2007版:兔
日期:2009-03-10 21:13:502014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11
9#
 楼主| 发表于 2011-1-20 14:21 | 只看该作者
原帖由 Yong Huang 于 2011-1-20 06:59 发表
Very well written. Indeed http://www.orafan.net/blog/352.html is more readable. Please remove the duplicate part starting with "这比BasicFile空闲空篇博文".

I have a strong feeling event 45050 is related to what is called in-memory dispensers. The event may flush or dump those dispensers. But it's *very* undocumented and I can't get it to work. More about these dispensers can be found in patent:
http://www.freepatentsonline.com/7664799.html

It's interesting that Oracle calls this technology SecureFiles and SecureFile LOBs. But I bet most users care more about the compression part of the technology than the security part.

Yong Huang

我找过内部网站,也是没有关于Event 45050的信息

使用道具 举报

回复
招聘 : 数据库管理员
论坛徽章:
9
生肖徽章2007版:牛
日期:2009-03-10 21:26:492010新春纪念徽章
日期:2010-01-04 08:33:082010年世界杯参赛球队:葡萄牙
日期:2010-02-22 14:35:242010新春纪念徽章
日期:2010-03-01 11:19:092010广州亚运会纪念徽章:射击
日期:2010-09-08 23:42:12ITPUB9周年纪念徽章
日期:2010-10-08 09:31:212010广州亚运会纪念徽章:拳击
日期:2010-10-30 00:46:582011新春纪念徽章
日期:2011-02-18 11:43:322011新春纪念徽章
日期:2011-03-01 08:49:39
10#
发表于 2011-1-20 17:37 | 只看该作者
原帖由 yexichang 于 2011-1-20 13:06 发表

这主要是依赖于你的数据。
压缩是压缩单条LOB,文本的压缩率高些,估计原理类似winrar之类的压缩
消除重复是多条LOB的内容完全一样的情况下使用,重复的LOB只记录一遍


也不是啊,我是从别的表导过来的,都是clob的说,我再研究研究哈。

使用道具 举报

回复

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

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表