Oracle行内链接不会引起USER_TABLES中CHAIN_CNT值变化

    前几天和群里网友讨论一个关于行内链接(intra-block chaining)的问题,问题非常有意思,恰好今天有空,顺便整理了一下这些知识点。

 

    问题描述:下面SQL,创建一个超过255列的表(实际为256列),然后插入几条数据,然后对表做ANALYZE分析过后,但是发现user_tables的CHAIN_CNT字段值为0,chained_rows表中没有记录,为什么会这样

declare
v_sql varchar2(32767) ;
begin
v_sql := 'create table t_chain1 ( ' ;
for i in 1..256 loop
v_sql := v_sql || 'id'||i||' number,' ;
end loop ;
v_sql := rtrim(v_sql, ',') || ')';
execute immediate v_sql;
end ;
/
 
insert into t_chain1(id256) values(1);
insert into t_chain1(id256) values(2);
insert into t_chain1(id256) values(3);
commit;
 
 
 
analyze table t_chain1 list chained rows;
analyze table t_chain1 compute statistics;
 
 
 
SQL> select table_name, num_rows, chain_cnt, avg_row_len from user_tables
  2  where table_name='T_CHAIN1';
 
TABLE_NAME                       NUM_ROWS  CHAIN_CNT AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
T_CHAIN1                                3          0         267
 
SQL> select * from chained_rows;
 
no rows selected

 

在分析这个问题前,我们要先了解一下Oracle数据库当中的Row Migration (行迁移) & Row Chaining (行链接)概念:

    当表中一行的数据不能在一个数据block中放入的时候,这个时候就会发生两种情况,一种是行链接(Row Chaining),另外一种就是行迁移(Row Migration)了。

   行链接产生在第一次插入数据的时候如果一个block不能存放一行记录的情况下。这种情况下,Oracle将使用链接一个或者多个在这个段中保留的block存储这一行记录,行链接比较容易发生在比较大的行上,例如行上有LONG、LONG RAW、LOB等数据类型的字段,这种时候行链接是不可避免的会产生的。

   当一行记录初始插入的时候事可以存储在一个block中的,由于更新操作导致行长增加了,而block的自由空间已经完全满了,这个时候就产生了行迁移。在这种情况下,Oracle将会迁移整行数据到一个新的block中(假设一个block中可以存储下整行数据),Oracle会保留被迁移行的原始指针指向新的存放行数据的block,这就意味着被迁移行的ROW ID是不会改变的。

 

当发生了行迁移或者行链接,对这行数据操作的性能就会降低,因为Oracle必须要扫描更多的block来获得这行的信息

row chain:When a row is too large to fit into any block, row chaining occurs. In this case, the Oracle devide the row into smaller chunks. each chunk is stored in a block along with the necessary poiters to retrive and assemble the entire row.

row migration:when a row is to be updated and it cannot find the necessary free space in its block, the Oracle will move the entire row into a new block and leave a pointer from the orginal block to the new location. This process is called row migration.

 

那么现在回到这个问题,我们先来看看表t_chain1的rowid,以及对应的文件号等信息:

select dbms_rowid.rowid_object(rowid)       obj#  ,
       dbms_rowid.rowid_relative_fno(rowid) rfile#,
       dbms_rowid.rowid_block_number(rowid) block#,
       dbms_rowid.rowid_row_number(rowid)   row#
from t_chain1 ;

 

我们看到这三条记录对应的行数据在BLOCK中的相对位置为1,3,5,那么说明当表的字段个数超过255时,是发生了行内链接的,关于这个,我们继续回顾一下行片段(row pieces)和行内链接(intra-block chaining)等概念

Row Format and Size

Oracle stores each row of a database table containing data for less than 256 columns as one or more row pieces. If an entire row can be inserted into a single data block, then Oracle stores the row as one row piece. However, if all of a row's data cannot be inserted into a single data block or if an update to an existing row causes the row to outgrow its data block, then Oracle stores the row using multiple row pieces. A data block usually contains only one row piece for each row. When Oracle must store a row in more than one row piece, it is chained across multiple blocks.

When a table has more than 255 columns, rows that have data after the 255th column are likely to be chained within the same block. This is called intra-block chaining. A chained row's pieces are chained together using the rowids of the pieces. With intra-block chaining, users receive all the data in the same block. If the row fits in the block, users do not see an effect in I/O performance, because no extra I/O operation is required to retrieve the rest of the row.

Each row piece, chained or unchained, contains a row header and data for all or some of the row's columns. Individual columns can also span row pieces and, consequently, data blocks. Figure 5-3 shows the format of a row piece:

 

这里面介绍了行内链接(intra-block chaining)概念,当一个表的列超过255列,ORACLE会把行记录分成两个或多个行片段(row piece),一个row piece包含255个字段,如果表中有312个字段,那么就会有三个行片段(row piece), 行内链接(intra-block chaining)只是多个行片段(row piece)通过rowid串联起来,这也是上面测试案例,你看到的对应rowid返回该行数据在BLOCK中的相对位置对应是1、3、5 ,而不是1、2、3的原因,因为行内链接(intra-block chaining)发生的同一个块内(block),所以它并不会产生额外的IO操作,也就是说不影响IO(当然这个要看你如何理解)。那么我使用alter system dump 来看看行在块里面的信息吧

 

去$ORACLE_BASE下面的udmp找到对应的trc文件,我实验中生成的文件为scm2_ora_20850.trc

cc:表示列数,fb:H是指行记录的头,L是指行记录的最后一列,F是指行记录的第一列. 实验结果跟理论是一致的。到这里似乎一直没有回到我们的问题来,那么我们先来看看官方文档对AVG_ROW_LEN的解释:

 

Number of rows in the table that are chained from one data block to another, or which have migrated to a new block, requiring a link to preserve the old ROWID

注意我标记为红色的部分,显然AVG_ROW_LEN记录的是发生了行链接或行迁移的行数,要么是数据从一个block迁移到另外一个block,要么是数据从一个block链接到另外一个block。而行内链接(intra-block chaining)是发生在同一个block内的,所以这里实验产生的行内链接并不会记录到AVG_ROW_LEN里面,所以这就解释了AVG_ROW_LEN为0,chained_rows没有记录的原因。

下面我们来构造一个行链接的案例,如下所示,新建表t_chain,使其一行的记录无法插入到一个block里面,那么当插入的时候,就会产生行链接,此时对表做ANALYZE分析过后,但是发现user_tables的CHAIN_CNT字段值不为0了,chained_rows表中也会有相关记录

declare
v_sql varchar2(32767) ;
begin
v_sql := 'create table t_chain ( ' ;
for i in 1..256 loop
v_sql := v_sql || 'id'||i||' char(36),' ;
end loop ;
v_sql := rtrim(v_sql, ',') || ')';
execute immediate v_sql;
end ;
/
 
declare
v_sql varchar2(32767) ;
begin
v_sql := 'insert into t_chain select ' ;
for i in 1..255 loop
v_sql := v_sql || '''it is only test'',' ;
end loop ;
v_sql := v_sql || '''it is only test'' from dual; commit;';
dbms_output.put_line( v_sql); --将生成的脚本执行2次
 
end ;
/
 
 
SQL> analyze table t_chain list chained rows;
 
Table analyzed.
 
SQL> analyze table t_chain compute statistics;
 
Table analyzed.
 
SQL>  select table_name, num_rows, chain_cnt, avg_row_len from user_tables
  2  where table_name='T_CHAIN' ;
 
TABLE_NAME                       NUM_ROWS  CHAIN_CNT AVG_ROW_LEN
------------------------------ ---------- ---------- -----------
T_CHAIN                                 2          2        9481
 
SQL> select count(1) from chained_rows;
 
  COUNT(1)
----------
         2
 
SQL> select * from chained_rows;
 
OWNER_NAME   TABLE_NAME   CLUSTER_NAME   PARTITION_NAME  SUBPARTITION_NAME   HEAD_ROWID      ANALYZE_T
----------- ------------ --------------- -------------- ----------------- ------------------ ---------
SYS             T_CHAIN                                       N/A          ACOhqAABAAAVMLAAA 10-JUL-16
SYS             T_CHAIN                                       N/A          AACOhqAABAAAVMNAAA 10-JUL-16
 
SQL> 

 

 

参考资料:

https://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2105.htm#REFRN20286

http://docs.oracle.com/cd/B19306_01/server.102/b14220/schema.htm#i4383

http://docs.oracle.com/cd/B28359_01/server.111/b28318/schema.htm#CNCPT1129

 

时间: 2024-11-12 19:05:21

Oracle行内链接不会引起USER_TABLES中CHAIN_CNT值变化的相关文章

ASP.NET Aries 入门开发教程6:列表数据表格的格式化处理及行内编辑

前言: 为了赶进度,周末也写文了! 前几篇讲完查询框和工具栏,这节讲表格数据相关的操作. 先看一下列表: 接下来我们有很多事情可以做. 1:格式化 - 键值的翻译 对于"启用"列,已经配置了格式化 #是否,已经可以看到效果了. 对于分类ID列,通常显示的是分类名称,而不是ID值. 可是分类名称不在文章表里,在文章分类表,怎么关联格式化呢? 我们有文章分类表: 所以我们写个下拉配置: 然后在配置表头里把它配置上: 效果: PS:通过自定义语句来翻译下拉项的注意事项: 1 2 3 1:翻译

CSS行内对齐的黑魔法

本文和以前的文章类似,orange 尽量带给大家分享实际项目中的坑怎么填,当然只是提供思想,方法很多欢迎讨论,还有就是对于刚上手前端的新人不是特别友好,没关系,涉及到基础知识我会对应的进行指引,给出链接或给出提示,大家可以自行 Google(百度). 说到行内对齐大家可能会想到类似水平对齐,垂直对齐总结类型的文章,既然我们叫 黑魔法 就不会是基础的对齐教程,基础教程的文章好多,大家想必都知道多种方法实现对齐 <!--more--> 项目背景 还是 orange 所在公司的移动端项目,上案例 截

如何通过站内链接布置让热门词到首页

很多朋友都在不停的做友情连接,希望自己的网站一些关键词在搜索引擎教程有很好的排名,方不知内链对网站优化教程也起到的重要的角色哦,好了我们来分析一下如何通过站内链接布置让热门词到首页吧. 内链的建设有5个常见的方法: 1.网站导航:很多时候网站的导航往往是网站的病种关键词,每更新一个页面就给这些病种一个内链,久而久之,这样的内链是有点强大的. 2.锚点关键词链接:比如某篇文章或者某个地方提到了妇科医院这个词,那妇科医院就可以做一个链接连接到主页上面去,这样就完成锚文本的链接,不过一片文章做1到3个

javascript行内脚本小小探讨

如果可能,尽量不要出现行内脚本,因为行内脚本会导致一系列问题,包括 页面混乱,难以阅读还有维护(想想一个大约1000行代码的网页,html标签跟js代码混杂在一起是何等的壮观,加上不合理的代码格式,那简直就是噩梦) 可重用性差(采用外部脚本链接,js代码可为多个页面共用) 重复下载(采用外部脚本链接,js代码可被浏览器缓存,避免不必要的重复下载) 由于阻塞下载问题,会导致页面加载渲染速度严重变慢(原因比较复杂,涉及js基本的加载机制以及代码依赖,以及当行内脚本置于CSS样式表后可能导致的延迟问题

[HTML/CSS]盒子模型,块级元素和行内元素

目录 概述 盒子模型 块级元素 行内元素 可变元素 总结 概述 在div+css中,了解块级元素和行内元素还是非常有必要的,比如:对行内元素使用width属性就会失效.虽然自己不是做前端的,但是,在项目中,曾经也弄过从前端布局,也吃过这方面的亏.今天,群里有朋友问起这个,就趁着学习一下,也算是查漏补缺吧,虽然,谈不上精通,但是了解,还是很有必要的. 盒子模型 css盒子模型分为两种,一种是遵循w3c标准的标准盒子模型,另外一种就是IE盒子模型. 标准盒子模型 IE盒子模型 通过上面两张图可以看出

站内链接应该怎么去优化 总结的小经验分享

小猫相信站长小伙伴们都知道站外链接对网站排名的重要性,每天在A5.站长网.推一把.搜外等网站幸幸苦苦的发着外链,看着自己网站的排名上升下降的, 自己的心也跟着七上八下的.小猫在这里提醒一下各位站长小伙伴们:关注站外链接建设的同时也不要忽略了站内链接的建设和所起到的作用,两方面同时兼顾,你 的网站才会做的更好,站长小伙伴们你们说小猫说的对不对呢? 外部链接大部分情况下是不好控制的,而且要经过很长时间的积累才会达到效果,但是内部链接的建设却完全都在站长小伙伴自己的掌握中的,为什么要放弃站内链接而去死

经典电影:用站内链接做好本站热门关键词

链接是指从一个网页指向一个目标,目标可以是另一个网页,也可以是相同网页上的不同位置.路径不同分内部链接.锚点链接和外部链接.方法有绝对链接,相对链接.大家都知道外部链接对网站排名的重要性,但大部分情况下是不好控制的,而且要经过很长时间的积累,内部链接却完全在自己的控制之下,如果把内链做好了也是可以优化本站热门关键词的.下面就几个优化站内链接的应用我们共同学习. 1.查看百度.GOOGLE对本站每天的收录及排名. 收录及排名都可以在站长网上查询收录了多少,并是否有关键词排名;然后到百度指数里查询有

CSS块元素和行内元素的相互转换

块元素和行内元素可以使用display进行相互转换 display:inline ->转为行内元素(例如div) display:block ->转为块元素(例如a) 例: <html> <head> <title>块元素和行内元素的相互转换</title> <link rel="stylesheet" style="text/css" href="test.css" />

Css块内元素和行内元素

行内元素(inline element),又叫内联元素: 内联元素可容纳文本或者其它内联元素,常见的内联元素有<span>.<a>.<input>. 块元素(block element): 块元素一般都从新行开始,可以容纳文本.其它内联元素和其它块元素. 即使内容不满一行,块元素也要把整行占满,而且会换行显示,常见的块元素有<div>.<p>. 某些CSS属性可能对行内元素不生效,这与浏览器的版本和类型有关, 因此,要尽可能使用块元素定位. 例: