搜索
查看: 1317|: 0

【Oracle】Oracle行迁移和行链接

[复制链接]

205

主题

5

回帖

755

积分

高级会员

积分
755
发表于 2014-10-17 15:34:43 | 显示全部楼层 |阅读模式
本帖最后由 MEI 于 2014-10-17 15:49 编辑

行迁移和行链接都会导致Oracle性能下降,这篇文章将介绍什么是行迁移和行链接,它们带来的问题,如何来判断它们,并提供了解决它们的办法。

什么是行迁移和行链接行迁移

Oracle的数据块会保留部分空间供以后更新使用,通常的数据块结构如下:

PCTFREE定义一个块保留的空间百分比,默认是10,表示当数据块的可用空间低于10%后,就不可以被insert了,只能被update(具体看下面的PCTFREE介绍)。
当一条记录被更新时,数据库引擎首先会尝试在它保存的数据块中寻找足够的空闲空间,如果没有足够的空闲空间可用,这条记录将被拆分为两个部分,第一个部分进包括指向第二个部分的rowid,该部分任然保留在原来的数据块中,第二个部分包含所有的具体数据,将保存到另外一个新的数据块中,这个就成为行迁移。

为什么不将整行都放到新的数据块中?
原因是这样会导致该行数据rowid发生变化,而rowid被存储在索引中,也有可能被客户端临时保存在内存中,rowid的变化可能导致查询错误。

PCTFREE介绍


PCTFREE可以在建表的时候指定:

  1. <font color="rgb(51, 51, 51)"><font face="宋体">create table test1 pctfree 20 as select rownum as id from all_objects where rownum <= 1000;
  2. </font></font>
复制代码

    这里指定表test1的PCTFREE为20,通过下面的方式可以查看该值:

  1. <font color="rgb(51, 51, 51)"><font face="宋体">select table_name, pct_free from user_tables where table_name = 'TEST1';

  2. TABLE_NAME  PCT_FREE
  3. ---------------------------
  4. TEST1       20</font></font>
复制代码
    在创建了表格后你可以通过alter table来调整PCTFREE值:
  1. <font color="rgb(51, 51, 51)"><font face="宋体">alter table test1 pctfree 15;</font></font>
复制代码


行链接

行链接和行迁移不同,行链接是当一条记录太大,在一个数据块中无法存入,这时会被拆分为2个或以上的部分,存储在多个块中,这多个块之间会构造一个链,如下:

行迁移是由于更新导致的,而行链接的原因则可能为:
1)直接插入大的记录;
2)更新记录导致记录大于一个数据块,在这时,这样记录可能会同时变为行迁移和行链接。

行迁移和行链接带来的问题

行迁移不会影响全扫描(全扫描更多介绍请看“Oracle性能分析4:数据访问方法之全扫描”),因为第一个部分不包含数据,会被直接跳过;但对于通过rowid进行访问(索引扫描或者直接使用rowid查询),则开销会翻倍,主要由于一次读取需要访问两个块。
     行链接则和数据访问方式无关,每次访问到第一个记录片段之后,都需要通过rowid去访问其他的记录片段。
     行迁移和行链接也会影响行级锁,因为每个记录片段都需要持有锁,锁的开销和记录片段的个数的增长成正比。

确定行迁移和行链接

确定行迁移和行链接可以使用下面几种方法。

查看v$sysstat和v$sesstat视图

该视图中统计项table fetch continued row可以确认是否出现了行迁移和行链接。

  1. <font color="rgb(51, 51, 51)"><font face="宋体">select name,value from v$sysstat where name = 'table fetch continued row';

  2. NAME                        VALUE
  3. -----------------------------------------------
  4. table fetch continued row   27455
  5. </font></font>
复制代码


但这个值只能提示你数据库的某个地方存在行迁移或者行链接,如果要评估导致的影响,你需要和table scan rows gotten和table fetch by rowid的统计信息对比。

查看具体表的行迁移和行链接信息

对指定表执行:

  1. <font color="rgb(51, 51, 51)"><font face="宋体">analyze table <table_name> list chained rows</font></font>
复制代码
    如果发现了行链接或者行迁移的记录,它们的rowid就会被记录到CHAINED_ROWS这张表中,该表可以使用$ORACLE_HOME/rdbms/admin目录下的UTLCHAIN.SQL或UTLCHN1.SQL脚本创建,建表语句如下:
  1. create table CHAINED_ROWS (
  2.   owner_name         varchar2(30),
  3.   table_name         varchar2(30),
  4.   cluster_name       varchar2(30),
  5.   partition_name     varchar2(30),
  6.   subpartition_name  varchar2(30),
  7.   head_rowid         urowid,
  8.   analyze_timestamp  date
  9. );
复制代码
     下面的存储过程将可以用来分析符合条件的所有表:
  1. begin
  2.   for obj in (select owner, object_name
  3.                 from dba_objects
  4.                where object_type = 'TABLE'
  5.                  and <other conditions>) loop
  6.     dbms_output.put_line(obj.owner || '.' || obj.object_name);
  7.     execute immediate 'analyze table ' || obj.owner || '.' ||
  8.                       obj.object_name || ' list chained rows';
  9.   end loop;
  10. end
复制代码
     然后通过查看CHAINED_ROWS表中的数据发现哪些表中存在行迁移和行链接:
  1. select table_name,head_rowid from CHAINED_ROWS

  2. TABLE_NAME  HEAD_ROWID
  3. --------------------------------------
  4. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAAAdAAA
  5. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAAAdAAG
  6. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAAAmAAI
  7. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAGpRAAH
  8. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAN0lAAD
  9. IND[        DISCUZ_CODE_174        ]nbsp;       AAAAACAABAAAN0oAAE
  10. ......
复制代码
     在这里我们可以看到那些表的那些行存在行迁移和行链接,但并不知道具体是行迁移和行链接,我们可以通过计算记录的长度,再将该长度和块大小进行比较,从而识别出他们具体是行迁移还是行链接。
     计算一行的长度使用下面的语句:

  1. select vsize(<col1>) + vsize(<col2>) + ... + vsize(<col3>) from <table> where rowid = '<rowid>';
复制代码
     数据库的块大小在参数db_block_size中保存,参看参数的方法详见“Oracle参数查看方法小结”。
表统计信息中查看行迁移和行链接

表DBA_tables的chain_cnt字段表示行迁移和行链接的数量信息,但dbms_stats包不会收集这个统计信息,该值始终为0。


  1. TABLE_NAME  CHAIN_CNT
  2. ---------------------------
  3. IND[        DISCUZ_CODE_45        ]nbsp;       0
复制代码
   通过下面的SQL语句可以收集该信息:

  1. analyze table ind$ compute statistics;
复制代码

然后再次查看:

  1. select table_name,chain_cnt from dba_tables where table_name = 'IND[/font][/color][/p][p=28, 2, left][color=rgb(51, 51, 51)][font=宋体]但该方法会导致被分析表的所有对象的统计信息都被覆盖,因此,在实践中不推荐使用。[/font][/color][/p][b]解决办法[/b][p=28, 2, left][color=rgb(51, 51, 51)][font=宋体]行迁移和行链接的解决办法不同,因此在处理前一定要区分清楚是行迁移还是行链接。[/font][/color][/p][b]行迁移[/b][p=28, 2, left][color=rgb(51, 51, 51)][font=宋体]首先我们应该避免行迁移,方法是在原块中保留足够的空闲空间,即调整PCTFREE参数值,值的大小需要评估记录扩展的平均大小。
  2. 当出现了行迁移后,则只能通过移动数据来解决,具体的方式有:
  3. 1)通过导出、导入或者ALTER TABLE MOVE对表进行重整;
  4. 2)将迁移的数据复制到临时表中,在原表上删除再重新插入这些数据。[/font][/color][/p][b]行链接[/b][p=28, 2, left][color=rgb(51, 51, 51)][font=宋体]处理行链接只能增加数据块的大小,但在一些情况下,可以通过将常用字段放在表的前面,不常访问的字段放在表的末尾来提高某些查询的效率(由于Oracle查询时只会取查询相关的字段)。[/font][/color][/p]
  5. ;

  6. TABLE_NAME  CHAIN_CNT
  7. ---------------------------
  8. IND$        13
复制代码

但该方法会导致被分析表的所有对象的统计信息都被覆盖,因此,在实践中不推荐使用。

解决办法

行迁移和行链接的解决办法不同,因此在处理前一定要区分清楚是行迁移还是行链接。

行迁移

首先我们应该避免行迁移,方法是在原块中保留足够的空闲空间,即调整PCTFREE参数值,值的大小需要评估记录扩展的平均大小。
当出现了行迁移后,则只能通过移动数据来解决,具体的方式有:
1)通过导出、导入或者ALTER TABLE MOVE对表进行重整;
2)将迁移的数据复制到临时表中,在原表上删除再重新插入这些数据。

行链接

处理行链接只能增加数据块的大小,但在一些情况下,可以通过将常用字段放在表的前面,不常访问的字段放在表的末尾来提高某些查询的效率(由于Oracle查询时只会取查询相关的字段)。


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

本版积分规则

大数据中国微信

QQ   

版权所有: Discuz! © 2001-2013 大数据.

GMT+8, 2024-11-15 20:58 , Processed in 0.059003 second(s), 24 queries .

快速回复 返回顶部 返回列表