分析和测试行链接(Row Chaining)及行迁移(Row Migrating)

来源:互联网 发布:破解软件3687474扣 编辑:程序博客网 时间:2024/06/08 01:49

 原来想出来的测试方法过于简单,没有考虑一些临界情况,经过讨论和网络上的信息,发现测试的想法是很重要的,测试的角度不对,也是不能将本质能够真正的理解,下面介绍我学习行链接(Row Chaining)及行迁移(Row Migrating)的分析和验证过程:

一、行迁移

1、新建一张表,设置pctfree =20:

create table BB
(a1  varCHAR2(2000),
 a2  varCHAR2(2000),
 a3  varCHAR2(2000),
 a4  varCHAR2(2000),
 a5  varCHAR2(2000),
 a6  varCHAR2(2000),
 a7  varCHAR2(2000),
 a8  varCHAR2(2000),
 a0  number(10))
 tablespace TBS_DAIMIN
  pctfree 20
  pctused 40
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );


  2、测试思路:

先向表中插入一条记录a,给两个字段赋制值,那么这条记录a大概占用了4k。
然后向表中插入一条记录b,给一个字段赋值,那么记录b大概占用了2k。a+b=6k,此时差不多刚好满足pctfree的要求,如果在添加新记录的时候会插入的下一个数据库块中。如果更新a或b的时候可以占用那20%的预留。

declare
tem_str varCHAR2(2000);
begin
tem_str:=null;
FOR i IN 1..2000 loop
tem_str:=tem_str||'1';
end loop;
insert into BB
(a0,a1,a2,a3,a4,a5,a6,a7,a8)values(1,tem_str,null,null,null,null,null,null,null);
commit;
insert into BB
(a0,a1,a2,a3,a4,a5,a6,a7,a8)values(2,tem_str,tem_str,null,null,null,null,null,null);
commit;
end;

此时的所用的数据块以及行信息如下:

select t.a0,dbms_rowid.rowid_object(rowid) data_object_id#,
       dbms_rowid.rowid_relative_fno(rowid) rfile#,
       dbms_rowid.rowid_block_number(rowid) block#,
       dbms_rowid.rowid_row_number(rowid) row#
  from BB t;


        A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         1           31937         11        162          0
         2           31937         11        162          1

 

实验一:更新记录b,使记录b增长到2个字段,这个时候会占用那20%的预留,这个块可以容纳下
这个两条记录,不发生行迁移。

declare
tem_str varCHAR2(2000);
begin
tem_str:=null;
FOR i IN 1..2000 loop
tem_str:=tem_str||'1';
end loop;
update BB
set a2=tem_str
 where a0=1;
commit;
end;

此时的所用的数据块以及行信息如下:

        A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         1           31937         11        162          0
         2           31937         11        162          1

 

实验二:更新记录b,使记录b增长到3个字段,这个时候那20%的预留不足以容纳b的增长,这个时候
会发生行迁移,整条记录b被迁移到下一个数据块
declare
tem_str varCHAR2(2000);
begin
tem_str:=null;
FOR i IN 1..2000 loop
tem_str:=tem_str||'1';
end loop;
update BB
set a3=tem_str
 where a0=1;
commit;
end;

此时的所用的数据块以及行信息如下:    

   A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         2           31937         11        162          1
         1           31937         11        162          0

之后做下面的插入数据操作,发现数据块以及行信息如下:

insert into BB(a1,a2,a3) values('ssssss','ssssss','ssssss');
commit;

     A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         2           31937         11        162          1
         1           31937         11        162          0
                     31937         11        163          1  --新插入的数据

对于新插入的数据则存放到了下一个数据块中的第二行中去,可以看出第一行已经被前一个块中的行迁移操作将原来的数据存放到第二个数据块中的第一行中去了。

实验三:更新记录b,使记录b增加到了4个字段,这个时候那20%的预留不足以容纳b的增长,我的理解我觉得此时增加了4个字段,第二个数据块也已经放不下,则会再行链接到第三个数据块,但是这个更新相对于第一个数据块还是行迁移,相对于第二个是数据块来说则是行链接,此时我觉得行迁移和行链接混合的操作。

declare
tem_str varCHAR2(2000);
begin
tem_str:=null;
FOR i IN 1..2000 loop
tem_str:=tem_str||'1';
end loop;
update BB
set a4=tem_str,
    a5=tem_str,
    a6=tem_str,
    a7=tem_str
where a0=1;
commit;
end;

此时的所用的数据块以及行信息如下: 

    A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         2           31937         11        162          1
                     31937         11        163          1
         1           31937         11        162          0

插入一条数据发现  所用的数据块以及行信息如下:

insert into BB(a1,a2)values('ssss','sssss');
commit;

       A0 DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
---------- --------------- ---------- ---------- ----------
         2           31937         11        162          1
                     31937         11        163          1
         1           31937         11        162          0
                     31937         11        165          1--新插入的块已经是从165块的第二行开始了

说明行164块和163块剩余的可用空间以及165块的第一行数据被A0=1这行数据占用;

上面是我的理解,网络上的同伴分析是下面所说的:

按理来说会发生行迁移,可是此时没有没发生行迁移,最后的结果比较类似于行链接。

猜想原因:如果此时发生的是行迁移的话,新的记录b会被迁移到下一个数据库,而记录b的大小为
10k左右,下一个块也不够容纳,只能在发生行链接。这样查询的记录b的话就要关联三个数据块,
效率比较低下。而如果不发生行迁移的话,记录b正好可以被这两个块容纳,查询b的时候仅仅需要
关联两个数据块,相对第一种情况效率高。oracle在行迁移的时候会根据实际情况进行优化,总是
以一种比较合理的方式来存储数据。

二、行链接

1、新建表,含有LONG类型:

-- Create table
create table TEST1
(
  AA LONG,
  BB VARCHAR2(1024),
  CC NUMBER(10)
)
tablespace TBS_DAIMIN
  pctfree 10
  pctused 40
  initrans 1
  maxtrans 255
  storage
  (
    initial 64K
    minextents 1
    maxextents unlimited
  );
2、测试过程

先插入6条数据

declare
temp_str varchar2(1024);
temp long;
begin
temp_str:=null;
for i in 1..1024
loop
temp_str:=temp_str||'1';
end loop;
for i in 1..7 loop
insert into test1
(aa,bb,cc)values('1',temp_str,i);
commit;
end loop;
end;

所用的数据块信息如下:

DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
--------------- ---------- ---------- ----------
          31939         12        618          0
          31939         12        618          1
          31939         12        618          2
          31939         12        618          3
          31939         12        618          4
          31939         12        618          5
          31939         12        618          6

再插入一行数据

declare
temp_str varchar2(1024);
begin
for i in 1..1024
loop
temp_str:=temp_str||'1';
end loop;
insert into test1
(aa,bb,cc)values('1',temp_str,10);
commit;
commit;
end;

所用的数据块信息如下:

DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
--------------- ---------- ---------- ----------
          31939         12        618          0
          31939         12        618          1
          31939         12        618          2
          31939         12        618          3
          31939         12        618          4
          31939         12        618          5
          31939         12        618          6
          31939         12        619          0  --新插入的数据已经被链接到下一个块中的第一行中去

结论:

   行链接:当一行的数据插入造成一个数据块无法容纳时,此时oracle会将该条数据存放到该段的数据块链中,此时会增加 一个数据块来重新存储存储新的数据,原来的数据块上剩余的可用空间也会被充分利用;
   行迁移:当需要更新原来的一个数据块中的一条数据时,由于更新后的该条数据过大造成该数据块的可用空间无法容纳时, 此时该行数据会被迁移到新的数据块中,并且被迁移的数据行的位置上用指针替代不再存放数据并且指向新数据 块的指针,不再存放数据,有可能会新增加数据块用来存放更新后的数据,但是被更新的行的rowid是保持不变的;