Oracle表中含有255列以上时需要注意的(r12笔记第77天)
公众号:杨建荣的学习笔记 · 作者:杨建荣 · 发布:2017-05-27 23:40:28 · 原文链接

今天看JL(Jonathan Lewis)的一篇文章,真是费了不少的脑细胞,玩Oracle几十年的老司机,看问题的角度和深度果然不一样,当时看他的大作《Oracle核心技术》就花了我不少时间,还没有看完,一本薄薄的书能够蕴含如此的能量,做技术到了这个火候,让人深深佩服。
他的一篇博文,标题很简单,就是“255 again”看来是一个很经典的问题,我就简单抓取一些测试的思路和脚本来说说。
原文在链接 https://jonathanlewis.wordpress.com/2017/05/23/255-again/
如果你的某张表列数超过255个,你就需要注意了,会有一些特别的问题出现,而对于这个问题的模拟,JL提供了一个脚本,会创建320个字段,然后对这个表插入一行数据,更新一行数据,然后根据block的dump来做一个分析和说明,脚本如下: remrem Script: wide_table_4.sqlrem Author: Jonathan Lewisrem Dated: May 2017remrem Last testedrem 12.2.0.1rem 12.1.0.2rem 11.2.0,4rem set pagesize 0set feedback off spool temp.sql prompt create table t1( select 'col' || to_char(rownum,'fm0000') || ' varchar2(10),'from all_objectswhere rownum <= 320; prompt col0321 varchar2(10)prompt )prompt / spool off @temp set pagesize 40set feedback on insert into t1 (col0010, col0280) values ('0010','0280');commit; update t1 set col0320 ='0320';commit; column file_no new_value m_file_nocolumn block_no new_value m_block_no select dbms_rowid.rowid_relative_fno(rowid) file_no, dbms_rowid.rowid_block_number(rowid) block_no, dbms_rowid.rowid_row_number(rowid) row_nofrom t1; alter system flush buffer_cache;
脚本执行后,会创建一个含有320个字段的表,然后对标所在的dump做一个trace。
ntab=1nrow=2frre=-1fsbo=0x16fseo=0x1e54avsp=0x1e3etosp=0x1f130xe:pti[0] nrow=2 offs=00x12:pri[0] offs=0x1e7a0x14:pri[1] offs=0x1e54block_row_dump:tab 0, row 0, @0x1e7atl: 49 fb: -------- lb: 0x2 cc: 40nrid: 0x014000a7.0col 0: *NULL*col 1: *NULL*col 2: *NULL*...col 37: *NULL*col 38: *NULL*col 39: *NULL*tab 0, row 1, @0x1e54tl: 38 fb: --H-F--- lb: 0x2 cc: 25nrid: 0x014000a3.0col 0: *NULL*col 1: *NULL*col 2: *NULL*...col 22: *NULL*col 23: *NULL*col 24: *NULL*end_of_block_dump有几个点需要注意,这个块被分成了两部分,”row 1″所在的那部分这个块的起点(可以通过fb中的标记H,意思就是header),可以从末尾的cc看出涉及的列有25个,行的下一部分可以通过nrid来看,就是nrid: 0x014000a3.0转换过来就是5号数据文件,163号数据块,这个和row 1所在的数据库相同。
如果我们看row 0的时候,会根据基本信息得到,它涉及的列数有40个,40个列都是空的,这一行指向的下行地址是nrid: 0x014000a7.0这个地址转换过来是在5号数据文件的167号块,根据这一行中间的标注(为空),感觉是一个可有可无的部分。我们就继续对5号数据文件的167号块做一个dump,得到的信息如下:
fsbo=0x14fseo=0x1e76avsp=0x1e62tosp=0x1e620xe:pti[0] nrow=1 offs=00x12:pri[0] offs=0x1e76block_row_dump:tab 0, row 0, @0x1e76tl: 266 fb: -----L-- lb: 0x1 cc: 255col 0: *NULL*col 1: *NULL*col 2: *NULL*...col 251: *NULL*col 252: *NULL*col 253: *NULL*col 254: [ 4] 30 33 32 30end_of_block_dump 通过上面的信息可以发现,这是行数据的最后一部分,可以通过哪个L得到,(即last).
所以一个初步结论如下:
-
一般的insert语句会把使用到的280个列分成两部分(25,255),这个280列可以通过Insert语句看到。
insert into t1 (col0010, col0280) values ('0010','0280'); 2.在updae的场景中,我们把使用到的列从280升到了320
update t1 set col0320 ='0320';所以说在update的场景中,我们可以把列的使用情况从280改进到了320个列,这40个列在orale中会跟255为分界来处理,这样就是(40,295),然后把40列放在原来的数据块中,剩下的把255个列迁移到一个新的块中,所以这样一来,原来列的的分布就很有特点了,分配到了两个块中。后面还有对于ASSM在这个过程中的分析,限于篇幅和脑细胞数量,就暂时告一段落吧。

