yexichang
论坛徽章:
3
电梯直达
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 64bi t + 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 编辑 ]
使用道具 举报
回复
yexichang
论坛徽章:
3
8 # 楼主| 发表于 2011-1-20 13:06 | 只看该作者
原帖由
killkill_shadow 于 2011-1-20 11:32 发表
我也研究了一下 ,我试了一下压缩+消重竟然占用了更到的空间。
这主要是依赖于你的数据。 压缩是压缩单条LOB,文本的压缩率高些,估计原理类似winrar之类的压缩 消除重复是多条LOB的内容完全一样的情况下使用,重复的LOB只记录一遍
使用道具 举报
回复
yexichang
论坛徽章:
3
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的信息
使用道具 举报
回复
转载于:https://my.oschina.net/rootliu/blog/1623516