row migeration and row chain

row migeration:当发出update导致记录行长增加,block的剩余空间不足以存放这条记录,就会产生行迁移,发生行迁移时rowid不会改变,原来的block中会用一个指针存放这条记录在新的block中的地址,发生行迁移会对性能产生影响,因为读这条记录会读两个BLOCK。

row chain:当一个BLOCK不足以存放下一条记录的时候,就会发生行连接,这个时候oracle会把这条记录分成几个部分,分别存放在几个block中,然后把这几个block chain起来。行连接同样会影响性能,因为读一条记录至少会读两个BLOCK.

下面来模拟row migeration ,row chain ,然后解决掉这两个问题。

row migeration

SQL> create table test1(x number,y varchar2(100)) pctfree 0;

Table created.
SQL> create table test2(x number,y varchar2(100)) pctfree 20;

Table created.
SQL> begin
  2  for i in 1..3000 loop
  3  insert into test1 values(i,'robinson');
  4  insert into test2 values(i,'luobingsen');
  5  end loop;
  6  commit;
  7  end;
  8  /

PL/SQL procedure successfully completed.
SQL> analyze table test1 compute statistics;

Table analyzed.

SQL> c/test1/test2
  1* analyze table test2 compute statistics
SQL> /

Table analyzed.

SQL> select chain_cnt from dba_tables where table_name='TEST1';

 CHAIN_CNT
----------
         0  

SQL> c/TEST1/TEST2
  1* select chain_cnt from dba_tables where table_name='TEST2'
SQL> /

 CHAIN_CNT
----------
         0
SQL> update test1 set y='robinsonluobingsen';

3000 rows updated.

SQL> c/test1/test2;
  1* update test2 set y='robinsonluobingsen'
SQL> /

3000 rows updated.

SQL> commit;

Commit complete.
SQL> analyze table test1 compute statistics;

Table analyzed.

SQL> c/test1/test2;
  1* analyze table test2 compute statistics
SQL> /

Table analyzed.
SQL> select chain_cnt from dba_tables where table_name='TEST1';

 CHAIN_CNT
----------
      1771  test1表有1771行发生了行迁移(注意,chain_cnt记录的是行迁移和行连接的数量,不要以为这个值大于0就发生了行迁移,也可能是行连接,此时要分析表的结构,查看到底是行连接或者是行迁移

SQL> c/TEST1/TEST2;
  1* select chain_cnt from dba_tables where table_name='TEST2'
SQL> /

 CHAIN_CNT
----------
       510  test2表有510行发生了行迁移
可以 alter table move 命令消除行迁移,以及降低HWM,不过这个时候这个应用不能访问该表,而且该表上的index会无效,因为move之后的ROWID变了,此时需要重新创建索引(rebulid)。

SQL> alter table test1 move;

Table altered.

SQL> analyze table test1 compute statistics;

Table analyzed.

SQL> select chain_cnt from dba_tables where table_name='TEST1';

 CHAIN_CNT
----------
         0   行迁移消除了
SQL> alter table test2 move;

Table altered.

SQL> analyze table test2 compute statistics;

Table analyzed.

SQL> select chain_cnt from dba_tables where table_name='TEST2';

 CHAIN_CNT
----------
         0  行迁移和消除了
row chain

SQL> show parameter db_block_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192
SQL> create table test3(a char(2000),b char(2000),c char(2000),d char(2000),e char(2000));

Table created.
我block size 为8k,也就是说一个block能存下大约8 k 的数据,(实际上小于8k,因为block header,tail 需要占用空间),也就是8192 byte,但是我创建的表的一行要占10000
byte,所以这个时候一个block 肯定不能存下一条记录。

SQL> insert into test3 values('robinson','luoluo','oracle','dba','aaaaa');

1 row created.

SQL> commit;

Commit complete.
SQL> analyze table test3 compute statistics;

Table analyzed.
SQL> select chain_cnt from dba_tables where table_name='TEST3';

 CHAIN_CNT
----------
         1   可以看到发生了行连接

要消除行连接,我们需要将block size 改大 ,db_block_size 是不能更改的,但是我们可以在创建tablespace 的时候指定 blocksize ,如果要创建这样的 tablespace ,需要首先指定 db_nk_cache_size ,然后 通过move 命令 将 发生了行连接的表 move 到 blocksize 较大的 tablespace.

SQL> show parameter db_16k

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_16k_cache_size                    big integer 12M
SQL> create tablespace rowchain blocksize 16384;

Tablespace created.  注意我使用了OMF,这样不需指定数据文件名和大小,由ORACLE自动管理

SQL> alter table test3 move tablespace rowchain;

Table altered.
SQL> analyze table test3 compute statistics;

Table analyzed.
SQL>  select chain_cnt from dba_tables where table_name='TEST3';

 CHAIN_CNT
----------
         0  可以看到行连接消除了



原文地址:https://www.cnblogs.com/hehe520/p/6330696.html