服务器 频道

Oracle数据库中行迁移/行链接的问题之一

  二、行迁移/行链接的检测
  
  通过前面的介绍我们知道,行链接主要是由于数据库的db_block_size不够大,对于一些大的字段没法在一个block中存储下,从而产生了行链接。对于行链接我们除了增大db_block_size之外没有别的任何办法去避免,但是因为数据库建立后db_block_size是不可改变的(在9i之前),对于Oracle9i的数据库我们可以对不同的表空间指定不同的db_block_size,因此行链接的产生几乎是不可避免的,也没有太多可以调整的地方。行迁移则主要是由于更新表的时候,由于表的pctfree参数设置太小,导致block中没有足够的空间去容纳更新后的记录,从而产生了行迁移。对于行迁移来说就非常有调整的必要了,因为这个是可以调整和控制清除的。
  
  如何检测数据库中存在有了行迁移和行链接呢?我们可以利用Oracle数据库自身提供的脚本utlchain.sql(在$ORACLE_HOME/rdbms/admin目录下)生成chained_rows表,然后利用ANALYZE TABLE table_name LIST CHAINED ROWS INTO chained_rows命令逐个分析表,将分析的结果存入chained_rows表中。从utlchain.sql脚本中我们看到chained_rows的建表脚本,对于分区表,cluster表都是适用的。然后可以使用拼凑语句的办法生成分析所需要的表的脚本,并执行脚本将具体的分析数据放入Chained_rows表中,例如下面是分析一个用户下所有表的脚本:
  
  SPOOL list_migation_rows.sql
  
  SET ECHO OFF
  
  SET HEADING OFF
  
  SELECT ''ANALYZE TABLE '' || table_name || '' LIST CHAINED ROWS INTO chained_rows;'' FROM user_tables;
  
  SPOOL OFF
  
  然后查询chained_rows表,可以具体查看某张表上有多少的行链接和行迁移。
  
  SELECT table_name, count(*) from chained_rows GROUP BY table_name;
  
  当然,也可以查询v$sysstat视图中的’table fetch continued row’列得到当前的行链接和行迁移数量。
  
  SELECT name, value FROM v$sysstat WHERE name = ''table fetch continued row'';
  
  可以使用如下的脚本来直接查找存在有行链接和行迁移的表,自动完成所有的分析和统计。
  
  accept owner prompt " Enter the schema name to check for Row Chaining (RETURN for All): "
  prompt
  prompt
  accept table prompt " Enter the table name to check (RETURN for All tables owned by &owner): "
  prompt
  prompt
  set head off serverout on term on feed off veri off echo off
  !clear
  prompt
  declare
  v_owner varchar2(30);
  v_table varchar2(30);
  v_chains number;
  v_rows number;
  v_count number := 0;
  sql_stmt varchar2(100);
  dynamicCursor INTEGER;
  dummy INTEGER;
  cursor chains is
  select count(*) from chained_rows;
  cursor analyze is
  select owner, table_name
  from sys.dba_tables
  where owner like upper(''%&owner%'')
  and table_name like upper(''%&table%'')
  order by table_name;
  begin
  dbms_output.enable(64000);
  open analyze;
  fetch analyze into v_owner, v_table;
  while analyze%FOUND loop
  dynamicCursor := dbms_sql.open_cursor;
  sql_stmt := ''analyze table ''||v_owner||''.''||v_table||'' list chained rows into chained_rows'';
  dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
  dummy := dbms_sql.execute(dynamicCursor);
  dbms_sql.close_cursor(dynamicCursor);
  open chains;
  fetch chains into v_chains;
  if (v_chains != 0) then
  if (v_count = 0) then
  dbms_output.put_line(CHR(9)||CHR(9)||CHR(9)||''<<<<< Chained Rows Found >>>>>'');
  v_count := 1;
  end if;
  dynamicCursor := dbms_sql.open_cursor;
  sql_stmt := ''Select count(*) v_rows''||'' From ''||v_owner||''.''||v_table;
  dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
  dbms_sql.DEFINE_COLUMN(dynamicCursor, 1, v_rows);
  dummy := dbms_sql.execute(dynamicCursor);
  dummy := dbms_sql.fetch_rows(dynamicCursor);
  dbms_sql.COLUMN_VALUE(dynamicCursor, 1, v_rows);
  dbms_sql.close_cursor(dynamicCursor);
  dbms_output.put_line(v_owner||''.''||v_table);
  dbms_output.put_line(CHR(9)||''---> Has ''||v_chains||'' Chained Rows and ''||v_rows||'' Num_Rows in it!'');
  dynamicCursor := dbms_sql.open_cursor;
  sql_stmt := ''truncate table chained_rows'';
  dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
  dummy := dbms_sql.execute(dynamicCursor);
  dbms_sql.close_cursor(dynamicCursor);
  v_chains := 0;
  end if;
  close chains;
  fetch analyze into v_owner, v_table;
  end loop;
  if (v_count = 0) then
  dbms_output.put_line(''No Chained Rows found in the ''||v_owner||'' owned Tables!'');
  end if;
  close analyze;
  end;
  /
  set feed on head on
  prompt
  
0
相关文章