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 可以看到行连接消除了