Oracle行迁移和行链接

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

什么是行迁移和行链接

行迁移

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

PCTFREE定义一个块保留的空间百分比,默认是10,表示当数据块的可用空间低于10%后,就不可以被insert了,只能被update(具体看下面的PCTFREE介绍)。

当一条记录被更新时,数据库引擎首先会尝试在它保存的数据块中寻找足够的空闲空间,如果没有足够的空闲空间可用,这条记录将被拆分为两个部分,第一个部分进包括指向第二个部分的rowid,该部分任然保留在原来的数据块中,第二个部分包含所有的具体数据,将保存到另外一个新的数据块中,这个就成为行迁移。

为什么不将整行都放到新的数据块中?

原因是这样会导致该行数据rowid发生变化,而rowid被存储在索引中,也有可能被客户端临时保存在内存中,rowid的变化可能导致查询错误。

PCTFREE介绍

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

create table test1 pctfree 20 as select rownum as id from all_objects where rownum <= 1000;

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

select table_name, pct_free from user_tables where table_name = 'TEST1';

TABLE_NAME	PCT_FREE
---------------------------
TEST1		20

在创建了表格后你可以通过alter table来调整PCTFREE值:

alter table test1 pctfree 15;

行链接

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

行迁移是由于更新导致的,而行链接的原因则可能为:

1)直接插入大的记录;

2)更新记录导致记录大于一个数据块,在这时,这样记录可能会同时变为行迁移和行链接。

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

行迁移不会影响全扫描(全扫描更多介绍请看“Oracle性能分析4:数据访问方法之全扫描”),因为第一个部分不包含数据,会被直接跳过;但对于通过rowid进行访问(索引扫描或者直接使用rowid查询),则开销会翻倍,主要由于一次读取需要访问两个块。

行链接则和数据访问方式无关,每次访问到第一个记录片段之后,都需要通过rowid去访问其他的记录片段。

行迁移和行链接也会影响行级锁,因为每个记录片段都需要持有锁,锁的开销和记录片段的个数的增长成正比。

确定行迁移和行链接

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

查看v$sysstat和v$sesstat视图

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

select name,value from v$sysstat where name = 'table fetch continued row';

NAME						VALUE
-----------------------------------------------
table fetch continued row	27455

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

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

对指定表执行:

analyze table <table_name> list chained rows

如果发现了行链接或者行迁移的记录,它们的rowid就会被记录到CHAINED_ROWS这张表中,该表可以使用$ORACLE_HOME/rdbms/admin目录下的UTLCHAIN.SQL或UTLCHN1.SQL脚本创建,建表语句如下:

create table CHAINED_ROWS (
  owner_name         varchar2(30),
  table_name         varchar2(30),
  cluster_name       varchar2(30),
  partition_name     varchar2(30),
  subpartition_name  varchar2(30),
  head_rowid         urowid,
  analyze_timestamp  date
);

下面的存储过程将可以用来分析符合条件的所有表:

begin
  for obj in (select owner, object_name
                from dba_objects
               where object_type = 'TABLE'
                 and <other conditions>) loop
    dbms_output.put_line(obj.owner || '.' || obj.object_name);
    execute immediate 'analyze table ' || obj.owner || '.' ||
                      obj.object_name || ' list chained rows';
  end loop;
end;

然后通过查看CHAINED_ROWS表中的数据发现哪些表中存在行迁移和行链接:

select table_name,head_rowid from CHAINED_ROWS

TABLE_NAME	HEAD_ROWID
--------------------------------------
IND$		AAAAACAABAAAAAdAAA
IND$		AAAAACAABAAAAAdAAG
IND$		AAAAACAABAAAAAmAAI
IND$		AAAAACAABAAAGpRAAH
IND$		AAAAACAABAAAN0lAAD
IND$		AAAAACAABAAAN0oAAE
......

在这里我们可以看到那些表的那些行存在行迁移和行链接,但并不知道具体是行迁移和行链接,我们可以通过计算记录的长度,再将该长度和块大小进行比较,从而识别出他们具体是行迁移还是行链接。

计算一行的长度使用下面的语句:

select vsize(<col1>) + vsize(<col2>) + ... + vsize(<col3>) from <table> where rowid = '<rowid>';

数据库的块大小在参数db_block_size中保存,参看参数的方法详见“Oracle参数查看方法小结”。

表统计信息中查看行迁移和行链接

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

select table_name,chain_cnt from dba_tables where table_name = 'IND$';

TABLE_NAME	CHAIN_CNT
---------------------------
IND$		0

通过下面的SQL语句可以收集该信息:

analyze table ind$ compute statistics;

然后再次查看:

select table_name,chain_cnt from dba_tables where table_name = 'IND$';

TABLE_NAME	CHAIN_CNT
---------------------------
IND$		13

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

解决办法

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

行迁移

首先我们应该避免行迁移,方法是在原块中保留足够的空闲空间,即调整PCTFREE参数值,值的大小需要评估记录扩展的平均大小。

当出现了行迁移后,则只能通过移动数据来解决,具体的方式有:

1)通过导出、导入或者ALTER TABLE MOVE对表进行重整;

2)将迁移的数据复制到临时表中,在原表上删除再重新插入这些数据。

行链接

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

时间: 2024-10-19 03:26:05

Oracle行迁移和行链接的相关文章

ORACLE 行迁移和行链接

1. 行迁移 当发出update导致记录行长增加,block的剩余空间不足以存放这条记录,就会产生行迁移,发生行迁移时rowid不会改变,原来的block 中会用一个指针存放这条记录在新的block中的地址,发生行迁移会对性能产生影响,因为读这条记录会读两个BLOCK. 行迁移:导致应用需要访问更多的数据块,性能下降. 预防行迁移:1. 将数据块的PCTFREE调大:2. 针对表空间扩大数据块大小 消除行迁移的办法: 创建行迁移表,$ORACLE_HOME/rdbms/admin目录下的utlc

10、管理数据库存储(行迁移及行连接)

管理数据库存储 1block=8192bytes 案例1:行迁移 1.表中数据如何存储 create table test as select * from hr.employees; create index idx_test on test(employee_id); 只看执行计划,不执行结果. set autotrace traceonly statistics; select * from test where employee_id>0; 强制走索引 select /*+index(t

模拟Oracle行迁移和行链接

行链接消除方法创建大的block块------------------ 参考tom kyte的例子----------------------------------------------创建4k blocksize的表空间SQL> alter system set db_4k_cache_size=1m scope=both; System altered.SQL> create tablespace tbs1 datafile '/u01/app/oracle/oradata/test/

Oracle 行链接(Row chaining) 与行迁移(Row Migration)

场景:如果VarChar和VarChar2更经常修改,且修改的数据长度每次都不一样,这会引起“行迁移”现象 概念: 行链接(Row chaining) 与行迁移(Row Migration)当一行的数据过长而不能插入一个单个数据块中时,可能发生两种事情:行链接(row chaining)或行迁移(row migration). 行链接当第一次插入行时,由于行太长而不能容纳在一个数据块中时,就会发生行链接.在这种情况下,oracle会使用与该块链接的一块或多块数据块来容纳该行的数据.行连接经常在插

消除行链接、行迁移

行迁移和行链接是经常接触到的一个概念.行链接是记录太大,一个数据块无法存储,oracle就会将其存储在相链接的块中,如果记录中数据类型包括:LONG.LONG RAW.LOB等数据类型时,行链接则无法避免了,可以在AWR实例活动统计部分的table fetch continued row分析可以看出当前数据库中链接行的数量:行迁移是指在update时,数据块已满,记录更新后记录长度增加了,oracle会将整条记录迁移到新的块中,行迁移后ROWID是不变的.参考ID 102989.1消除行链接和行

深入解析SQL Server行迁移记录

总长未超过8060字节,变长和定长列存储在同一页/记录中的记录称为行内数据记录.行内记录最常见了,因为一般的记录长度都是在8060字节内的.行内记录理论上都是存放在一个页面中的,这种记录的结构相对简单,格式也相对固定. 行内记录会包含一些常见数据类型的列,如int.char(n).varchar(n).datetime2.real.money等.这些类型的数据有变长的也有定长的,所以在更新变长列的数据时,会使记录长度增大,到超出空闲空间容量时,这样即使此记录小于8060字节,也会造成此记录在这一

模拟行迁移试验

1.创建scott模式 [[email protected] dbs]$ sqlplus '/as sysdba' SQL*Plus: Release 10.2.0.1.0 - Production on Mon Feb 17 14:59:02 2014 Copyright (c) 1982, 2005, Oracle. All rights reserved. Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0

【oracle11g,17】存储结构: 段的类型,数据块(行连接、行迁移,块头),段的管理方式,高水位线

一.段的类型: 1.什么是段:段是存储单元. 1.段的类型有: 表 分区表 簇表 索引 索引组织表(IOT表) 分区索引 临时段 undo段 lob段(blob ,clob) 内嵌表(record类型,table类型) 启动段 :打开数据库时要装入的数据字典系统信息,故在系统表空间内. 注意:smon 回收不用的临时段和undo段. 2.表: 表是存储数据的逻辑单位. 表的功能: 存储.管理数据的基本单元, 表的类型: 普通表:堆表, 例:查询表的行的平均长度 AVG_ROW_LEN 平均长度

Oracle设置列宽,行数

Oracle列宽.行数设置 在命令行进行简单的数据库操作,有时显示出来的数据出现换行情况,为了让数据更加清晰美观,这时可以设置行宽和列宽. 首先设置行数:set pagesize 300(根据个人要求设置); 然后设置列宽:set linesize 200/150(根据个人要求设置); 最后看一下效果,如下: 设置之前 设置之后 这样所有数据显示明了清晰,赶快试一下吧. 原文地址:https://www.cnblogs.com/s1-myblog/p/10888403.html