Oracle数据表默认值列添加与行迁移(Row Migration)--转


在笔者之前的文章中,已经探讨过给一个数据表添加有默认值列是一项

非常“危险”的事情,特别是在在线生产环境下。给一张大数据表添加

有默认值列,最直接的有下面几个严重危害:

 

1、系统高负荷运行,消耗大量资源。添加列操作是一次性的DDL操作,

生成大量的Redo Log记录;

2、长期数据表锁定,阻碍生产系统作业。添加数据列期间,对数据表添

加独占锁,此时阻碍其他DML操作;

3、破坏原有存储结构,造成大量的行迁移(Row Migration)数据。在

每个数据行尝试添加进默认值,进行膨胀的同时,由于rowid的特性,

会引起严重的行链接情况,损害原有数据表存储结构;

 

本文主要想聊聊由于默认值添加带来的行链接(Row Migration)现象

1、从Row Migration现象谈起

Row Migration本质上是一种由于Oracle存储特性和数据行定位特性而

发生的一种现象。在Oracle中,所有的数据行都是保留在数据块单元上

的。一个数据块可以容纳若干条数据(通常条件下)。一些数据列,如

varchar2类型,大部分情况下都是根据输入数据的长度进行空间分配。

 

那么,如果数据行列填入了更大的数据,也就是空间发生了拓展。数据

块存储上就会发生何种变化呢?每个数据块都会预留一部分的空闲空间

,作为数据行变化预留位置。如果长度继续拓展,那么会发生什么呢?

 

Oracle会尝试将这个数据行拷贝出,找个新的数据块进行存储。这样,

就可以放下数据块。那么,一个新的问题出现了,就是Rowid问题。

 

在Oracle中,Rowid是定位一条记录的物理地址。Rowid包括数据文件相

对编号、对象号、数据块号和Slot行号。Rowid普遍作为数据行的标记

,保存在相关的索引叶子节点上。但是,当一个数据行被转移存储到另

一个数据块,本质上物理存储位置已经发生变化。索引等对象中包括的

Rowid面临着失效的问题。

 
Oracle解决这个问题是通过“虚拟门牌”的方法。这个数据行位置虽然

已经到另外的地方,但是对应的Rowid并没有发生变化。当我们检索数

据,Server Process定位到原来的位置时,它会找到一个转换跳转地址

,那里面记录着真正的Rowid地址。这个就是发生了Row Migration。

 

Row Migration给系统性能带来了很多潜在的问题。比如,一行数据原

来只需要寻找一个数据块记录,现在就需要寻找多个数据块才可以。这

样就是带来的性能问题。

 

我们在进行默认值数据行添加的时候,就会带来Row Migration的爆发



 

2、Row Migration与默认值列添加

 

下面我们通过实验,来证明Row Migration的出现。我们选择11gR2环境

进行实验。

 
 

SQL> select * from v$version;
 

BANNER

-------------------------------------------------------------

-------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 -

Production

PL/SQL Release 11.2.0.1.0 - Production

CORE       11.2.0.1.0        Production

 

SQL> create table t as select object_id from dba_objects where

1=0;

Table created

 

--添加若干条记录;

SQL> insert into t select object_id from dba_objects where

rownum<100;

99 rows inserted


SQL> commit;

Commit complete

 

 

数据表T,在存储结构和空间分配上情况如下:

 

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade =>

true);

PL/SQL procedure successfully completed

 

SQL> select bytes, blocks,extents from user_segments where

segment_name='T';

 

    BYTES    BLOCKS   EXTENTS

---------- ---------- ----------

    65536         8         1

 
SQL> select blocks from user_tables where table_name='T';

 

   BLOCKS

----------

        1

 

 

User_segment中记录着给数据段分配的总空间,但这并不代表全部的

HWM位置。User_tables中的blocks,才代表HWM下数据块的个数。从上

面的结果看,HWM下一共只有一个数据块。从rowid分析看,实际也的确

如此。

 
SQL> select dbms_rowid.rowid_block_number(rowid) blockno,

count(*) from t group by dbms_rowid.rowid_block_number(rowid);

 
  BLOCKNO  COUNT(*)

---------- ----------

    85857        99

 

 

下面我们进行数据列添加。

 

 

SQL> alter table t add vc varchar2(1000) default lpad

('T',500,'T');

Table altered

 

Executed in 0.078 seconds

 

 

对应的空间使用情况如下:

 
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade =>

true);

PL/SQL procedure successfully completed
 

Executed in 0.141 seconds

 

SQL> select blocks from user_tables where table_name='T';

 

   BLOCKS

----------

       12

 

Executed in 0.016 seconds

 

 

SQL> select bytes, blocks,extents from user_segments where

segment_name='T';

 

    BYTES    BLOCKS   EXTENTS

---------- ---------- ----------

   131072        16         2

 

SQL> select dbms_rowid.rowid_block_number(rowid) blockno,

count(*) from t group by dbms_rowid.rowid_block_number(rowid);

 

  BLOCKNO  COUNT(*)

---------- ----------

    85857        99

 

Executed in 0.016 seconds

 

 

上面的情况可以看出,Oracle的数据表T已经推高了水位线HWM到12个块

,从空间分配也分配了新的extent使用。

 

但是,所有数据行rowid没有变化。所有数据行的“门牌号”都没有变

化,但是存储呢?很诡异的增加了。正常容量下,数据块情况应该是如

下:

 

 

SQL> create table t_bak as select * from t;

 

Table created

 

SQL> exec dbms_stats.gather_table_stats(user,'T_BAK',cascade

=> true);

 

PL/SQL procedure successfully completed

 

SQL> select bytes, blocks,extents from user_segments where

segment_name='T_BAK';

 

    BYTES    BLOCKS   EXTENTS

---------- ---------- ----------

   131072        16         2

 

SQL> select blocks from user_tables where table_name='T_BAK';

 

   BLOCKS

----------

        8

 

SQL> select dbms_rowid.rowid_block_number(rowid) blockno,

count(*) from t_bak group by dbms_rowid.rowid_block_number

(rowid);

 

  BLOCKNO  COUNT(*)

---------- ----------

    86589        14

    86588        14

    86585        14

    86586        14

    86591        14

    86590        14

    86587        14

    86592         1

 

8 rows selected

 

 

下面,我们来证明发生了行链接情况。

 

3、数据表行链接检验

 

Analyze语句一度是非常流行的收集数据表统计量的操作方式。但是随

着dbms_stats包的成熟推广,analyze在统计量收集方面的功能已经渐

渐弱化。但是,Oracle依然保留了这个语句的两个基本功能:对数据表

进行行链接(Row Migration)检测和索引健康程度检测。

 

下面使用analyze语句进行数据表T的检测。首先我们需要创建分析结果

的容纳数据表。

 

--调用ORACLE_HOME下的脚本;

SQL>@?/rdbms/admin/utlchain.sql

 

Table created.

 

SQL> desc chained_rows;

 Name                                     Null?   Type

 ----------------------------------------- -------- ---------

-------------------

 OWNER_NAME                                        VARCHAR2

(30)

 TABLE_NAME                                        VARCHAR2

(30)

 CLUSTER_NAME                                      VARCHAR2

(30)

 PARTITION_NAME                                    VARCHAR2

(30)

 SUBPARTITION_NAME                                 VARCHAR2

(30)

 HEAD_ROWID                                        ROWID

 ANALYZE_TIMESTAMP                                 DATE

 

SQL> create public synonym chained_rows for chained_rows;

 

Synonym created.

 

SQL> grant all on chained_rows to public;

 

Grant succeeded.

 

 

分析数据表,如下:

 

--检验数据行Row Migration情况;

SQL> analyze table t list chained rows into chained_rows;

Table analyzed

 

Executed in 0.125 seconds

 

--发生Row Migration次数;

SQL> select count(*) from chained_rows;

 

 COUNT(*)

----------

       86

 

Executed in 0.016 seconds

 

SQL> select head_rowid from chained_rows where rownum<5;

 

HEAD_ROWID

------------------

AAASUCAABAAAU9hAAN

AAASUCAABAAAU9hAAO

AAASUCAABAAAU9hAAP

AAASUCAABAAAU9hAAQ

 

Executed in 0.016 seconds

 

SQL> select * from t where rowid='AAASUCAABAAAU9hAAQ';

 

 OBJECT_ID VC

---------- --------------------------------------------------

------------------------------

       38

TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

TTTTTTTTTTTTTTTTTT

 

Executed in 0.016 seconds

 

 

在99行记录中,发生了86次行链接Row Migration情况。

 

 

4、结论

 

解决Oracle Row Migration的方法,就是进行数据表重构,重新对存储

结构和Rowid进行整理。我们说,在生产环境下,进行有默认值数据列

的添加操作,会引起一系列的问题,要三思而行。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/15489979/viewspace-742252/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/15489979/viewspace-742252/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值