数据库迁移

查看数据文件的使用情况

包括内容:数据文件大小,已经used空间,free空间,hwm信息
select /*+ ordered use_hash(a,b,c) */
 a.file_id,
 a.file_name,
 a.filesize,
 b.freesize,
 (a.filesize - b.freesize) usedsize,
 c.hwmsize,
 c.hwmsize - (a.filesize - b.freesize) unsedsize_belowhwm,
 a.filesize - c.hwmsize canshrinksize
  from (select file_id, file_name, round(bytes / 1024 / 1024) filesize
          from dba_data_files) a,
       (select file_id, round(sum(dfs.bytes) / 1024 / 1024) freesize
          from dba_free_space dfs
         group by file_id) b,
       (select file_id, round(max(block_id) * 8 / 1024) HWMsize
          from dba_extents
         group by file_id) c
 where a.file_id = b.file_id
   and a.file_id = c.file_id
 order by unsedsize_belowhwm desc
 
结果说明:
File_id : 文件编号
File_name: 文件名称
File_size: 数据文件占用磁盘空间大小
Freesize:文件中被标记为free的空间大小
Usedsize: 使用的空间大小。
Hwmsize: 已经分配出去的空间大小,如果希望通过alter database datafile … resize integerM回收空间,将需要这个值作为参考,不能回收到这个值之下,否则会报错。Freee_belowhwm_size: 在HWM(高水位标记线之下的空闲空间数),这个是理论上的可以回收的空间大小。
Curr_can_shrink: 这个是实际大小与HWM标记之间的差,就是还没有分配出去的空间大小。

对想收缩的表空间中的表及索引进行rebuild

建立测试表空间
create tablespace HWM datafile ‘/oradata/HWM01.dbf’ size 5000M;
alter tablespace HWM add datafile '/oradata/HWM02.dbf' size 5000M;

move表空间的long类型

LONG类型的数据超难管理,不能通过move来传输,也不能通过诸如insert t1 select long_col from t2的方式(或者使用游标可以解决这个问题)请注意在设计中尽量避免使用LONG类型。

检查当前表空间中的LONG类型字段。

select /*+use_hash(ds,dtc)*/
 ds.tablespace_name,
 ds.owner || '.' || ds.segment_name,
 ds.segment_type,
 dtc.DATA_TYPE,
 dtc.COLUMN_NAME
  from dba_tab_columns dtc, dba_segments ds
 where dtc.TABLE_NAME = ds.segment_name
   and dtc.OWNER = ds.owner
   and ds.tablespace_name not in
       ('SYSTEM', 'CWMLITE', 'EXAMPLE', 'UNDOTBS2', 'HWM')
   and data_type = 'LONG'

对long类型的数据处理的一个简单的方法实将LONG类型字段直接修改为LOB类型。
select /*+use_hash(ds,dtc)*/
 'alter table ' || ds.owner || '.' || ds.segment_name || ' modify ' ||
 dtc.COLUMN_NAME || ' clob;'
  from dba_tab_columns dtc, dba_segments ds
 where dtc.TABLE_NAME = ds.segment_name
   and dtc.OWNER = ds.owner
   and ds.tablespace_name not in
       ('SYSTEM', 'CWMLITE', 'EXAMPLE', 'UNDOTBS2', 'HWM')
   and data_type = 'LONG'

move表空间下的普通table及index

Move一个表到另外一个表空间时,索引不会跟着一块move,而且会失效。
Alter index index_name rebuild;
Alter index pk_name rebuild;

如果我们需要move索引到另外一个表空间,则需要使用rebuild
Alter index index_name rebuild tablespace tbs_name;
Alter index pk_name rebuild tablespace tbs_name;

MOVE表生成SQL:
select ds.tablespace_name,
       'alter table ' || ds.owner || '.' || ds.segment_name ||
       ' move tablespace HWM;'
  from dba_segments ds
 where ds.tablespace_name ='FJNJJL'
   and ds.segment_type = 'TABLE';

MOVE索引生成SQL:
select ds.tablespace_name,
       'alter INDEX ' || ds.owner || '.' || ds.segment_name ||
       ' rebuild tablespace HWM;'
  from dba_segments ds
 where ds.tablespace_name = 'FJNJJL'
   and ds.segment_type = 'INDEX'

move表空间下的分区table及index

和普通表一样,索引也会失效,区别的仅仅是语法而已。

分区表move基本语法
如果是单级分区,则使用关键字partition,如果是多级分区,则使用subpartition替代partition。
如果分区或分区索引比较大,可以使用并行move或rebuild,parallel(degree 2)。

重建全局索引
Alter index global_index rebuild;

Alter index global_index rebuild tablespace tbs_name;

重建局部索引
Alter table tab_name modify partition partition_name rebuild unusable local indexes;

Alter index local_index_name rebuild partition partition_name tablespace tbs_name;

 Move分区表
select cname
  from (select rownum rm,
               'alter table ' || ds.owner || '.' || ds.segment_name ||
               ' move partition ' || ds.partition_name || ' tablespace HWM;' cname
          from dba_segments ds
         where ds.tablespace_name ='FJNJJL'
           and ds.segment_type = 'TABLE PARTITION') c
 where rm between 1 and 100;
循环执行上述语句,直到选不出结果。

alter table ODS.CR_PS_INVENTORY_ITEM move partition CR_PS_INVENTORY_ITEM_P070603 tablespace HWM;

重建全局索引
     Oracle的全局索引也存储在dba_segments中,并以index标志,
     而且其重建方式跟普通索引一致,所以在执行忘回导入的时候需要按照move 普通表;
     move分区表;move全局索引;move分区索引;move lob对象的顺序进行。

重建分区索引
    视图dba_part_indexes存储分区表的本地索引,查询发现当前系统中不存在本地索引,可以忽略。
    select
* from dba_part_indexes t where t.owner not in ('SYSTEM','SH')

move表空间下的LOB类型

在建立含有Lob字典的表时,oracle会自动为Lob字段建立两个单独的segment,
一个用来存放数据(segment_type=LOBSEGMENT),另一个用来存放索引(segment_type=LOBINDEX)。
默认他们会存储在和表一起的表空间。我们对表move时,LOB类型字段和该字段索引不会跟着move,必须使用单据的语句来执行该字段的move,
语法如下:
Alter table t321 move tablespace HWM;
Later table t321 move lob(en) store as (tablespace HWM);

 select 'alter table ' || dtc.owner || '.' || dtc.TABLE_NAME || ' move lob(' ||
       dtc.COLUMN_NAME || ') store as(tablespace HWM);'
  from dba_tab_columns dtc
 where dtc.OWNER = 'FJNJJL'
   and dtc.DATA_TYPE like '%LOB'

alter table DP22.D_KPI move lob(KPIFORM) store as(tablespace HWM);

执行完上述操作步骤后,我们检查tablespace的空间使用情况可以发现,所有相关数据文件的hwm都已经变为0,也就是说所有的空间都已经变为未分配状态。
但这时如果我们将数据文件dump出去,会发现原来的数据还在,只不过在数据字典中将其标识为未分配。

Move对象的逆顺序

普通表对象

将普通表对象和分区表对象按照其owner的不同从HWM临时表空间move到其默认的表空间中区。

select  ds.tablespace_name,'alter table '||ds.owner||'.'||ds.segment_name||' move tablespace '||du.default_tablespace||';'
from dba_segments ds , dba_users du
where ds.owner = du.username
  and ds.owner in ('CTL','DW','RPT','OD','ODS','TODS','FBI','DP22','DP23','TCLKING')
  and ds.tablespace_name = 'HWM'
  and ds.segment_type = 'TABLE';

SQL> alter table TODS.CR_PARTY_RELATIONSHIP move tablespace TODSD;

Table altered

SQL> alter table TODS.CR_PARTY_RELATIONSHIP_TYPE move tablespace TODSD;

Table altered

分区表对象

select cname
from (
select  rownum rm,'alter table '||ds.owner||'.'||ds.segment_name||' move partition '||ds.partition_name||' tablespace '||du.default_tablespace||';' cname
from dba_segments ds , dba_users du
where ds.owner = du.username
  and ds.owner in ('CTL','DW','RPT','OD','ODS','TODS','FBI','DP22','DP23','TCLKING')
  and ds.tablespace_name = 'HWM'
  and ds.segment_type = 'TABLE PARTITION'
) c
where rm between 1 and 500;

反复执行上述过程,直到没有记录可以选择。

SQL> alter table ODS.CR_PS_INVENTORY_ITEM move partition CR_PS_INVENTORY_ITEM_P080513 tablespace ODSD;

Table altered

SQL> alter table ODS.CR_PS_INVENTORY_ITEM move partition CR_PS_INVENTORY_ITEM_P080514 tablespace ODSD;

Table altered

索引对象

    索引对象存储的tablespace的命令标准为username+’I’,如果类似的表空间不存在,我们就将索引数据存储到用户的默认表空间中。所以我们可以使用下面的语句将index rebuild到对应的表空间中。

select  'alter INDEX '||ds.owner||'.'||ds.segment_name||' rebuild tablespace '||nvl(dt.tablespace_name,du.default_tablespace)||';'
from dba_segments ds , dba_users du, dba_tablespaces dt
where ds.owner = du.username
  and dt.tablespace_name(+) = du.username||'I'
  and ds.owner in ('CTL','DW','RPT','OD','ODS','TODS','FBI','DP22','DP23','TCLKING')
  and ds.tablespace_name = 'HWM'
  and ds.segment_type = 'INDEX'

LOB类型

Lob类型数据随着table对象存储在对象owner的默认表空间中。

select  'alter table '||dtc.owner||'.'||dtc.TABLE_NAME||' move lob('||dtc.COLUMN_NAME||') store as(tablespace '||du.default_tablespace||');'
from dba_tab_columns dtc,dba_users du
where dtc.OWNER = du.username
  and dtc.OWNER  in('CTL','DW','RPT','OD','ODS','TODS','FBI','DP22','DP23','TCLKING')
  and dtc.DATA_TYPE like '%LOB'

SQL> alter table FBI.TIME_FORMAT move lob(FORMAT) store as(tablespace FBI);

Table altered

SQL> alter table FBI.URLTABLE move lob(DETAIL) store as(tablespace FBI);

Table altered

SQL> alter table OD.PLAN_TABLE move lob(OTHER) store as(tablespace OD);

Table altered

收缩空闲表空间

首先,如果没有分配的空间不足100M,则不考虑收缩。

收缩目标:当前数据文件大小 - (没分配空间- 100M)×0.8
 
select /*+ ordered use_hash(a,c) */
  'alter database datafile '''||a.file_name||''' resize '
   ||round(a.filesize - (a.filesize - c.hwmsize-100) *0.8)||'M;',
  a.filesize,
  c.hwmsize
from
(
select file_id,file_name,round(bytes/1024/1024) filesize from dba_data_files
) a,
(
select file_id,round(max(block_id)*8/1024) HWMsize from dba_extents
group by file_id) c
where a.file_id = c.file_id
  and a.filesize - c.hwmsize > 100

检查磁盘当前剩余空间

$ bdf

/dev/vg01/lvol1    133120000 33173720 99166120   25% /oradata

小结

执行整个步骤之前,/oradata磁盘下的剩余空间不足6G,执行步骤之后我们看到,目前系统中有将近100G的剩余空间^_^。

效果明显。









迁移指定的Lob字段到指定的表空间
alter table NTLJ_ZHPK move tablespace FJNJJL lob (pic) store as(tablespace TS_NJJL_LOB)

posted @ 2011-05-19 15:51  吾爱易逝  阅读(626)  评论(0编辑  收藏  举报