行迁移

美国PVH DB存在行链接.通过我的检查,发现,我们的DB同样存在行迁移和行链接.ORACLE的dbms_stats.gather_schema_stats只会收集优化器统计信息,不会检测表的记录是否存在行迁移和行链接.(我原先被这个包给骗了,所以执行完dbms_stats.gather_schema_stats后一查数据字典:USER_TABLES,其中的字段chain_cnt值全为0).要检测表的记录是否存在row chain,需要用到ORACLE早先一点的命令:ANALYZE TABLE.所以我写了一个存储过程(P_analyze_schema)以检测DB:PVH91USRD中所有表存在行链接的情况.

         值得注意的是:数据字典 USER_TABLES.CHAIN_CNT的值是包含了行迁移和行链接的数目.请看ORACLE的解释:

CHAIN_CNT*  Number of rows in the table that are chained from one data block to another, or which have migrated to a new block, requiring a link to preserve the old ROWID

也就是说这个字段的值是行迁移和行链接的总数量,至于要知道具体行迁移有多少,行链接又是多少,ANALYZE TABLE这个命令没办法得到,只有通过DUMP BLOCK来区分(方法复杂,故没有去做).但首先我们要知道行迁移和行链接是两个不同的概念:

(1)行迁移: ORACLE一个BLOCK的DEFAULT SIZE是8K,事实上,一个BLOCK不可以存储8K的数据.一个BLOCK可以存储多少数据,由PCTFREE,PCTUSED参数控制(对于以前的手工管理的表空间而言).

PCTFREE:是指BLOCK保留空闲空间的百分比,用于UPDATE。对于已经插入到BLOCK的行而言,后面的UPDATE操作有可能使行的长度增加,PCTFREE就是用于容纳增加的那部分长度而保留的空闲空间。如果UPDATE时PCTFREE再也不能够容纳行增加的长度,则ORACLE会将整个行迁移到一个新的BLOCK,行的ROWID保留(不是太明白为什么ORACLE不改变ROWID),原来的BLOCK有一个指针指向ROW存放的新BLOCK。这就是行迁移。可见,行迁移是由于UPDATE操作所导致。从字面上理解,所谓迁移,肯定先有存在这一行,才能叫着迁移.

 

PCTUSED:是指BLOCK用于INSERT的百分比。对于INSERT操作,BLOCK可用于容纳新行的最大空间为Blocksize-pctfree-overhead.BLOCK数据存储已高于PCTUSEDORACLE会将该块从自由链表中移除,直到该块已使用空间降到PCTUSED以下,才会再次将此块重新加入到Freelist(这是ORACLE以前手工管理的表空间管理空闲块的原理,现在ORACLE推荐使用ASSM).

 

行迁移和行链接的检测:

除了我写的存储过程可以检测以外,一个简单的检测方法是:

  select b.NAME,a.VALUEfrom v$mystat a,v$statname b
   
where a.STATISTIC#=b.STATISTIC#
   
and b.NAME  like'table fetch continued row'

当有返回值时,可以知道表的数据存在行迁移和行链接。

 

行迁移和行链接的清除:

能过REBUILD数据来清除行迁移:

createtable MM_PM_temp asselect*from MM_PM;
truncatetable MM_PM;
insertinto MM_PM select*from MM_PM_temp

再重新分析表:

analyze table MM_PM compute statistics;

分析过后再查看:

select t.table_name,
      
t.num_rows,
      
t.chain_cnt,
      
t.avg_row_len,
      
round((t.chain_cnt / t.num_rows)*100,2)as "chained rows %"
 
from user_tables t
 
where t.chain_cnt >0

如果该表的chain_cnt变为0时,表示原先的chain_cnt全部是行迁移,而不是行链接。如果REBUILD数据后chain_cnt变少,但还大于0,则可以证明,这个表即包含行迁移,又包含真正的行链接。事实证明,行迁移是可以通过REBUILD数据和增加PCTFREE%来清除和减少发生频率的。注意,对于ASSMPCTUSEDFREELISTFREELIST GROUPS参数会被忽略。

 

但对于真正的行链接,只能通过将表移植到大的BLOCSIZE的表空间上,下面是我的实险:

创建一个16K的表空间:

CREATETABLESPACE LARGETBS   BLOCKSIZE16 K
   
LOGGING
   
DATAFILE'/data/app/oracle/oradata/ora33/LARGETBS_01.dbf'SIZE64MAUTOEXTENDONNEXT  10M
     MAXSIZEUNLIMITED
   
EXTENTMANAGEMENTLOCAL
   
SEGMENTSPACEMANAGEMENT  AUTO;

在创建的时候报了个ORA-的错,原因我们没有设定16DB_Buffer_cache,我们设定一下:

  altersystemset db_16k_cache_size=34603008;

将表MOVE16K的表空间:

altertable SRC_CS movetablespace LARGETBS;

altertable MM_PM movetablespace LARGETBS;

由于进行了迁移,表的索引会失效,所以我们要REBUILD索引:

alter index PK_SRC_CS rebuild;

alter index PK_MM_PM rebuild;

再重新分析:

analyze table SRC_CS compute statistics;

analyze table MM_PM compute statistics;

重新查询:

select t.table_name,
      
t.num_rows,
      
t.chain_cnt,
      
t.avg_row_len,
      
round((t.chain_cnt / t.num_rows)*100,2)as "chained rows %"
 
from user_tables t
 
where t.chain_cnt >0
 
orderby t.table_name

发现,这些表都没有ROW CHAIN了。可见,MOVE16K的表空间可以清除ROW CHAIN

一般来讲,一个表如果有多于256个字段,则发生ROW CHAIN的频率比较高。

 

对于包含long,long raw类型的行,发生ROW CHAIN的概率也比较大。因为long,long raw会尽量先在同一行中存储字段值。而对于CLOBBLOB等对象,一般来讲,会单独用另外的表空间来存放(oracle推荐这么做),发生ROW CHAIN的概率小一些。但是,有文档指出,当你没有为CLOB指定单独的表空间时,如果CLOB的实际值小4000 BYTEORACLE还是会将CLOB字段存放到同一个BLOCK,只有当CLOB的值大于4000 BYTEORACLE才会将该字段单独存放。如果真是这样的话,CLOB也会引起ROW CHAIN(如果CLOB和其它字段是同一表空间的话)

附件:

create or replace procedure p_analyze_schema is
  cursor
getdata is
    select
table_name
      from user_tables
     order by table_name;
 v_sqlstr varchar2(4000);
begin
  for
rec in getdata loop
    v_sqlstr:= 'analyze table  '||rec.table_name||' compute statistics';
    execute immediate(
v_sqlstr);
  end loop;
end
p_analyze_schema;

请慎重使用下面这个存储过程:

create or replace procedure p_calculate_rowlen is
  cursor
getdata is
    select
table_name
      from user_tables
     where table_name not in
           (
'mm_pm', 'mm_pm_history','src_cs', 'src_cs_history')
     order by
table_name;
  cursor
getdata2(p_tabname varchar2) is
    select
t.table_name, t.column_name
      from user_tab_columns t
     where t.table_name = p_tabname
       and t.data_type not in ('clob', 'blob')
     order by
t.column_id;
  v_sqlstr clob;
begin

  dbms_output.enable(1000000);
  for
rec in getdata loop
    v_sqlstr := ' ';
    for
rec2 in getdata2(rec.table_name) loop
      v_sqlstr := v_sqlstr || 'nvl(vsize(' || rec2.column_name || '),0)+';
    end loop;

    v_sqlstr := substr(v_sqlstr, 1, (length(v_sqlstr) - 1));
    v_sqlstr := 'insert into t_tab_row_len select  ''' || rec.table_name ||
                ''',rl from ' || ' (select  (' || v_sqlstr ||
                ') as rl  from  ' || rec.table_name || ')  where rl>=1000';
    begin
      execute immediate (
to_char(v_sqlstr));
      commit;
    exception
      when others then

        dbms_output.put_line(rec.table_name);
        return;
    end;
  end loop;
end
p_calculate_rowlen;

create table t_tab_row_len
(
  table_name varchar2(60),
  row_len    number(20)
)

 

 行链接:是指一个BLOCK不能容纳一行(行的长度太大),而必须将此行存放于几个BLOCK.行链接一般是在Insert时产生的.一个BLOCK能否用于insert是由PCTUSED控制

转自:http://blog.csdn.net/rainnyzhong/article/details/5374588

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值