前几天和群里网友讨论一个关于行内链接(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

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

  1. 【Oracle】Oracle 的过程化SQL(PLSQL)中NULL值的处理

    下面是NULL的几个注意点: 1.NULL值既不是空格也不是0. 2.给表插入值的时候,如果没有给列指定列值,则默认为NULL. 3.当算术表达式里包含NULL值时,其计算结果也是NULL值. 这时候 ...

  2. HTML中的行内元素和框元素详解

    定义 传统的块级元素定义中只是说明了在文档流中形成了一个块,在前后加换行,这里有些笼统. 其实框元素是指宏观上的框元素,它包括3种类型:1.本身就是块级元素 2.dispaly被设置为类block 3 ...

  3. css 块状元素与行内元素(内联元素)的理解

    块状元素: 它一般是其他元素的容器元素,可以容纳块状元素和行内元素,它默认是不会和其他元素同一行的,即相当于两个块状元素写一起是垂直布局的.最常用的是div和p 行内元素: 行内元素又称内联元素,它只 ...

  4. 04. H5标签有哪些?行内元素有哪些?块级元素有哪些?空(void)元素有哪些?行内元素和块级元素有什么区别?你工作中常用标签有什么?

    4. H5标签有哪些? 2)行内元素有哪些? a - 锚点 em - 强调 img - 图片 font - 字体设定 ( 不推荐 ) i - 斜体 input - 输入框 3)块级元素有哪些? add ...

  5. CSS行内元素

    一.典型代表 span a ,strong em del, ins 二.特点: 在一行上显示 不能直接设置宽高 元素的宽和高就是内容撑开的宽高. <style type="text/c ...

  6. 行内元素与块级元素的区别,行内块级元素在IE8-的兼容性

    行内元素与块级元素的区别 行内元素最好不要包裹块级元素,但是块级元素可以任意的包裹行内元素 行内元素如果其上一个元素也是行内元素,则他们会分布在统一水平线上,即在一行上排列,块级元素不论上一个元素是行 ...

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

    前言: 为了赶进度,周末也写文了! 前几篇讲完查询框和工具栏,这节讲表格数据相关的操作. 先看一下列表: 接下来我们有很多事情可以做. 1:格式化 - 键值的翻译 对于“启用”列,已经配置了格式化 # ...

  8. 1 background(复合属性)与font(复合属性) 2 行内块的间距问题 3 行内元素的margin 4 清除浮动 5定位的元素的层级 6 Border-radius: 边框半径

    1 background(复合属性)与font(复合属性): background: 颜色  图片的链接  是否平铺  背景位置 是否滚动.(可以随意调动或省略) Font: 粗度 字体风格 字体大小 ...

  9. [Latex]实现行内高亮

    Latex的行内高亮 前两天想要在做的小操作系统实验指导书里使用行内高亮,一开始虽然有命令 \mint{Language}|contents| 但是无奈只能实现跳行高亮,即不能实现行内高亮.即代码高亮 ...

随机推荐

  1. Redis系列三之持久化

    一.Redis持久化 Redis是一个支持持久化的内存数据库,redis需要经常将内存中的数据同步到磁盘来保证持久化. redis提供了不同级别的持久化方法: Snapshotting(快照,默认方式 ...

  2. Java的List排序

    有时需要对List排序,这时可以利用Collections的sort()方法来排序,不用自己再去排序. package myTest; import java.util.ArrayList; impo ...

  3. hibernate----1-1

    <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hi ...

  4. C#生成随机验证码

    使用YZMHelper帮助类即可 using System; using System.Web; using System.Drawing; using System.Security.Cryptog ...

  5. 袋鼠过河---DP

    题目:一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远,每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5, ...

  6. CI框架源码阅读笔记6 扩展钩子 Hook.php

    CI框架允许你在不修改系统核心代码的基础上添加或者更改系统的核心功能(如重写缓存.输出等).例如,在系统开启hook的条件下(config.php中$config['enable_hooks'] = ...

  7. Guava学习笔记:Immutable(不可变)集合

    不可变集合,顾名思义就是说集合是不可被修改的.集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变. 为什么要用immutable对象?immutable对象有以下的优点: 1.对不可靠的客 ...

  8. 【转】UTF-8汉字正则表达式

    原文链接:http://blog.csdn.net/wide288/article/details/30066639 $str = "编程";// if(!preg_match(& ...

  9. Webform(Linq增删改查)

    Linq高集成化的数据访问类,它会自动映射数据库结构,将表名完整映射成为类名,将列名完整映射成字段名数据库数据访问,能大大减少代码量.(1)Linq创建添加LINQ to SQL类,类名需与要连接的数 ...

  10. jQuery Wheel 环形菜单插件5种效果演示

    很酷的菜单-jQuery Wheel 环形菜单插件5种效果演示在线预览 下载地址 实例代码 <div class="container"> <!-- Top Na ...