琢磨了2天的行链接和行迁移的模仿终于告一段落,赶紧记之,与君分享,嘎嘎!
 
如何模仿行链接?
行链接好模仿,如下:
create table test (x int primary key ,a char(2000),b char(2000),
c char(2000),
d char(2000),
e char(2000)
) tablespace test2;
test2的块大小是8K,5个char(2000)的字段,这样每行记录约为10k。肯定超过一个块大小。
insert into test (x) values (1);
commit;

SQL> select * from CHAINED_ROWS
  2  ;

未选定行
此时还没产生行链接,

SQL> update test set a='test',b='test',c='test',e='test' where x=1;

已更新 1 行。

SQL> commit;

提交完成。

SQL> ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

SQL> select * from CHAINED_ROWS;

                  TABLE_NAME     HEAD_ROWID         
------------------------------ --------- ------------------------------                           

                      TEST               AAAMFaAAHAAACVCAAA
可见产生的是行链接,因为一个块的大小只有8k,而此时这条记录的大小已经约为10k,意味着将跨数据块存储。

那么请问,如何模仿行迁移呢?
下面是一种模仿行迁移的办法:

block的大小为:8k
test@ORCL>create table test (id int,name varchar2(4000),job varchar2(2200),sal varchar(2000) )
  2   pctfree 0 pctused 99;

表已创建。

test@ORCL>insert into test values(1,'dd','xx','sss');

已创建 1 行。

test@ORCL>insert into test values(2,'dx','xx','sss');

已创建 1 行。

test@ORCL>insert into test values(3,'dx','xx','sss');

已创建 1 行。

test@ORCL>insert into test values(4,'dx','xx','sss');

已创建 1 行。

test@ORCL>commit;

提交完成。

test@ORCL>update test set name=RPAD('Z',4000,'Z') where id=4;

已更新 1 行。

test@ORCL>commit;

提交完成。

test@ORCL>select dbms_rowid.rowid_block_number(rowid) as block_number from test;

BLOCK_NUMBER
------------
         106
         106
         106
         106

可见所有的记录都是在106号数据块里面。

test@ORCL>ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

test@ORCL>select * from CHAINED_ROWS;

此时并没有产生行链接或者行迁移。
----执行完上一条update的时候(也就是update test set name=RPAD('Z',4000,'Z') where id=4;
),此块剩下的大小不足4k;所以执行下面的update将肯定导致行迁移。
test@ORCL>update test set job=RPAD('J',2200,'J'),sal=RPAD('S',2000,'S') where id=3;

已更新 1 行。

test@ORCL>commit;

提交完成。


test@ORCL>ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

test@ORCL>select * from CHAINED_ROWS;

OWNER_NAME                     TABLE_NAME                     CLUSTER_NAME                   PARTITION_NAME
------------------------------ ------------------------------ ------------------------------ ------------------------------
SUBPARTITION_NAME              HEAD_ROWID         ANALYZE_TI
------------------------------ ------------------ ----------
TEST                           TEST
N/A                            AAAOqKAAKAAAABqAAC 25-1月 -10


test@ORCL>select id from test where rowid in (select head_rowid from chained_rows);

        ID
----------
         3
可见是ID为3的记录产生了行迁移。而此时ID为3的记录所在的块号是不会变化的,尽管是行迁移:

test@ORCL>select dbms_rowid.rowid_block_number(rowid) as block_number from test;

BLOCK_NUMBER
------------
         106
         106
         106
         106

-------下面将通过简单的delete insert 的方式来解决这个行迁移的问题:

test@ORCL>create table temp as select * from test  where rowid in (select head_rowid from chained_rows);

表已创建。

test@ORCL>delete from test  where rowid in (select head_rowid from chained_rows);

已删除 1 行。

test@ORCL>commit;

提交完成。

test@ORCL>select id from test;

        ID
----------
         1
         2
         4

test@ORCL>select id from temp;

        ID
----------
         3

test@ORCL>select * from chained_rows;

OWNER_NAME                     TABLE_NAME                     CLUSTER_NAME                   PARTITION_NAME
------------------------------ ------------------------------ ------------------------------ ------------------------------
SUBPARTITION_NAME              HEAD_ROWID         ANALYZE_TI
------------------------------ ------------------ ----------
TEST                           TEST
N/A                            AAAOqKAAKAAAABqAAC 25-1月 -10

而此时chained_rows表里还有之前的行迁移的统计信息,好,我们删了,从来来过:
test@ORCL>ANALYZE TABLE test LIST CHAINED ROWS;

表已分析。

test@ORCL>select * from CHAINED_ROWS;

未选定行

对表从新分析后,可见行迁移已经被干掉了。我们再来看看block number:


test@ORCL>select dbms_rowid.rowid_block_number(rowid) as block_number from test;

BLOCK_NUMBER
------------
         106
         106
         106
         107

test@ORCL>select dbms_rowid.rowid_block_number(rowid) as block_number from test
  2  where rowid=(select rowid from test where id=3);

BLOCK_NUMBER
------------
         107

可见test表里,id为3的记录已经被从106号数据块里放到了107号数据块里面,而不是像之前的那样:在106号数据块id=3的那条记录里存储了一个指向其他数据块的地址。此时id=3的记录已经被单独放到了107号数据块里。


总结:
行迁移可以通过简单的delete,insert该条数据的方式解决。而行链接的话delete和insert的方式是不能见效的。
行链接只有考虑使用更大的数据块,来解决。