future2012lg

博客园 首页 新随笔 联系 订阅 管理

在我们的数据仓库使用oracle其中有很多超级大表,这些表的分区方式基本都是range+hash分区或list+hash分区。使用时间字段进行range或list分区,再用用户ID进行子分区。不过最近有人反映有一张表select起来很慢,进过查看发现原来这个表只进行了list分区,没有进行hash子分区。讨论后决定对该表的分区方式进行改变:从list分区改为list+hash分区。操作过称如下:

 

1.前期准备

为了确定迁移策略先看看这个表有多大。

select owner, segment_name, sum(bytes) / 1024 / 1024 / 1024 size_G
  from dba_segments
 where owner = 'user'
   and segment_name = 'TABLE'

 

发现这个表有570多G。

这个表已经有二十多个分区,每个分区的记录数是将近10亿(是不是有点崩溃,这么大的表~)。

 

确定策略:为了不影响在线表的服务,先建一个预备表TABLE_NEW使用list+hash分区,然后一个分区一个分区的叫TABLE表的数据insert到TABLE_NEW表,再后将TABLE表改名为TABLE_OLD,将TABLE_NEW改成TABLE,最后对这个表给其他用户赋权限。

 

2. 倒出TABLE表的建表语句

 

通过查看TABLE表的建表DDL,得到建表语句。

 

查询数据库的object的DDL信息:
select dbms_metadata.get_ddl('TABLE','TABLE_NAME','user') from dual;
修改建表语句并建TABLE_OLD表
 
3. 数据迁移
迁移程序日下
#!/usr/bin/bash
LOGFILE=TABLE.log

sqlplus user/password@DB <<EOD  >> ${LOGFILE}
set serverout on size 1000000
set timing on
alter session enable parallel dml;
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

PROMPT Starting to insert into TABLE
select sysdate from dual;

declare
        v_commit        number;
        v_sql           varchar2(3000);
        error_msg       varchar2(300);
begin
        for rec in (select partition_name from dba_tab_partitions
                        where table_owner = 'user' and table_name = 'TABLE'
                        order by partition_name) loop
        begin
               v_sql :='insert /*+ append */into user.TABLE_NEW
                        (STATIS_MONTH,
                          ....
                          .....)                      
                  select STATIS_MONTH,
                    ......
                    ......
                    ......
               from user.TABLE  partition('||rec.partition_name||')';
          Execute Immediate v_sql;
              v_commit := Sql%Rowcount;
             
              commit;
             
              select sysdate from dual;
              dbms_output.put_line(rec.partition_name||' commit records'||v_commit);
         
          --如果一个分区出错,试下一个分区  
              exception
              when others then
                        error_msg := substr(sqlerrm, 1, 240);
                        dbms_output.put_line(||rec.partition_name||' - '||error_msg);
              end;
       
        end loop;
end;
exit;
EOD
 
 
确认每个分区的数据都迁移成功
 
4. --修改表名
 
sqlplus user/password@DB
rename TABLE to TABLE_OLD;
rename TABLE_NEW to TABLE;
 
5.对其他用户赋权限
posted on 2013-03-21 19:37  future2012lg  阅读(374)  评论(0编辑  收藏  举报