Oracle 重建表(rename)注意事项总结

一、概述
前一段时间,有一个DBA朋友在完成重建表(rename)工作后,第二天早上业务无法正常运行,出现数据无法插入的限制和错误,后来分析才发现,错误的原因是使用rename方式重建表以后,其它引用这个表的外键约束指向没有重新定义到这个重建的新表中,从而导致这些表在插入新数据时,违反数据完整性约束,导致数据无法正常插入。影响了业务大概有1个多小时,真是一次血淋淋的教训啊。
使用rename方式重建表是我们日常DBA维护工作中经常使用的一种方法,因为CTAS+rename这种配合方式,非常实用和高效。很多DBA朋友应该也都是用过rename方式重建表,而且重建完成以后也都一切正常,没有引起过问题。但是,我想说的是,使用rename重建表后,具体需要完成哪些扫尾工作你真的清楚吗??
这篇文章主要就是归纳当我们使用rename方式重建表后,需要进行哪些扫尾工作,如果你还不是很清楚,一定要仔细阅读这篇文章,同时在以后的重建表工作中矫正过来,否则,问题迟早有一天会降临到你的身边!

二、重建表的方式
这里先不谈其它,仅仅说一下重建表的方法。如下
1、为了确保所有表字段、字段类型、长度完全一样,我一般不建议使用CTAS方式来重建表。
2、一般我都是使用下面两种方法中的一个,来抽取表的定义
  • select dbms_metadata.get_ddl('TABLE',upper('&i_table_name'),upper('&i_owner')) from dual;
  • 使用PL/SQL developer类似这样的工具,来查看表定义语句
3、重新建一张_old类型的表(根据上面的抽取的表定义),然后使用insert /*+ append */ xx select xxx 方式完成数据的转换
4、最后使用rename方式倒换这两张表的名字


三、重建表注意事项
索引重建:这里最关键的是,重建后索引的名字是否必须和以前的一样,如果需要一样,则必须将当前使用的索引名字先rename,否则创建的时候会出现索引名字已经存在的错误,如下:
select 'alter index ' || owner || '.' || index_name || ' rename to ' ||
       substr(index_name, 1, 26) || '_old;'
  from dba_indexes a
 where a.table_owner = 'DBMON'
   AND A.table_name = 'DH_T';  
依赖对象重建:一般可以使用如下方式完成
select 'alter '||decode(type,'PACKAGE BODY','PACKAGE',type)||' '||owner||'.'||name||' compile;'
  from dba_dependencies a
 where a.referenced_name = 'DH_T'
   and a.referenced_owner = 'DBMON';  
注意:
1、这里重建的只是直接依赖对象,必须考虑那些间接依赖的对象(例如 view1依赖A表,view2依赖view1),查找方法和上面差不多
2、如果这些依赖对象中存在一些私有对象(例如dblink等),我们用DBA用户重新编译是会出现编译错误,对于这种对象,必须以对应对象的所属者才能编译成功。(也可用用10g以后新出现的代理权限来完成这类任务!)
针对PL/SQL代码(包、函数、过程等),是否存在私有对象的查找方法,如下:
select *
  from dba_source a
 where (a.owner, a.name) in
       (select owner, name
          from dba_dependencies b
         where b.referenced_name = 'DH_T'
           and b.referenced_owner = 'DBMON')
   and a.TEXT like '%@%';  
针对视图中是否存在私有对象的查找方法,如下(由于是long类型,必须得一个一个查看):
select *
  from dba_views a
 where (a.owner, a.view_name) in
       (select owner, name
          from dba_dependencies b
         where b.referenced_name = 'DH_T'
           and b.referenced_owner = 'DBMON'
           and b.type = 'VIEW')  
权限重建:可以使用如下语句
select 'grant ' || PRIVILEGE || ' on ' || owner || '.' || table_name ||
       ' to ' || grantee || ';'
  from dba_tab_privs
 where table_name = upper('&i_table_name')
   and owner = upper('&i_owner');

外键重建:对于外键,现在的业务数据逻辑很多都是在应用层来实现,因此表上的外键可能都非常少,因此,导致很多DBA都忘记需要检查和重建这一部分了,从而导致业务出现问题,本章最开始说的故障案例就是因为没有重建外键而引起,因此我们一定要提高警惕。可以使用如下语句查看,哪些表引用了重建表
select a.table_name,
       a.owner,
       a.constraint_name,
       a.constraint_type,
       a.r_owner,
       a.r_constraint_name,--被外键引用的约束名
       b.table_name  --被外键引用的表名
  from dba_constraints a, dba_constraints b
 where a.constraint_type = 'R'
   and a.r_constraint_name = b.constraint_name
   and a.r_owner = b.owner
   and b.table_name = 'FSPARECEIVEBILLTIME'
   and b.owner='';

物化视图:另外一个非常重要的依赖对象就是物化视图,一般来说,rename表以后,物化视图是不会有问题的,再次刷新时会自动编译,但是这可能会影响优化其选择执行计划,因此,建议手工直接编译这些失效的物化视图,如下
alter MATERIALIZED VIEW DH_T_MV compile; 
备注,其实这步已经包含在依赖对象重建部分了,单独拿出来是因为这个依赖对象非常重要,不容有任何意外

物化视图日志:物化视图日志是为了快速刷新准备的,而且从dba_dependencies 这张依赖表中无法查找出来的,但是,对于这个对象,我们一定要保持谨慎和敬畏,因为如果表上存在物化视图日志对象的话,那么这张表无法完成rename(在一个变更的晚上,其它什么都OK了,突然遇到一个这样的问题,还得找开发确认,是非常被动的,整个变更很有可能因为这个无法确认而取消),会直接报错,查找表上的物化视图日志对象方法如下:
select master,log_table
 from user_mview_logs a
where master in ('DH_T');  

备注:
  1. 我们可能还需要关注表字段类型,那些LOB、long字段都是我们重建表是需要考虑的
  2. 还有就是重建表是我们可能都会使用parallel+nologging模式来加快速度,一定要记得在重建完成后将这些属性修改回来。(以前遇到过一个案例,未将parallel属性改回来,导致执行计划选用并行,最终导致资源很快耗尽,CPU100%)
  3. 还有一些同步机制,如果同步依赖rowid,由于重建表rowid会该表,可能造成实时同步失败,这些都是我们需要考虑的
  4. 最后,在工作完成后,检查一下所有对象的有效性是一个不错的方案。(建议在重建前保存快照,重建后与前面的快照比较)
  5. 上面讲述的都是一些我们最常用的对象,其它一些很少使用的对象这里就不概述了
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
支持自动ORACLE大表分区: 版本进度: 31. 20110420 V2.2 支持任意表任意时间字段分区 以下为安装部署部分: 1.分区相关脚本部署执行顺序,安装前请确保该用户拥有管理员权限, 同时请执行GRANT CREATE ANY TABLE TO DBUSER, 因为使用到了动态的CREATE TABLE语句; 01) >AGGRE_ERROR_INFO_DDL.SQL 如果日志表AGGRE_ERROR_INFO已经存在,该步骤跳过。 02) >GET_MILLISECOND.SQL 如果函数GET_MILLISECOND已经存在,该步骤跳过。 03) >GET_DATE_FROM_MILLISECOND.SQL 如果函数GET_DATE_FROM_MILLISECOND已经存在,该步骤跳过。 04) >AGGRE_PM_PARTITIONF.SQL 2.注意事项: 01) >部署完后注意检查分区维护JOB[对应存储过程为AGGRE_PM_PARTITIONM], 如果有多个相同的分区维护JOB,则请删除后面创建的JOB,只保留一个分区维护JOB。 检查脚本如下:select t.what,t.* from user_jobs t 02) >本产品中使用的分区调度表名称为AGGRE_PARTITION_TASK,可以根据该表中信息观察分区情况。 以下为说明解释部分: 2.分区改造主过程:AGGRE_PM_PARTITIONF.SQL, 意思是PARTITIONING THE FIRST TIME; 参数解释如下: -- @PARAM VARCHAR2 PARTTABLENAME---可以指定对某个表大小大于等于TABLEONSIZE_M(单位为MB)的表进行按指定时间字段的自动分区; -- @PARAM NUMBER TABLEONSIZE_M---大表自动分区起始大小,单位为兆字节(MB),如不想指定具体大小则置0即可; -- @PARAM NUMBER PARTINTERVAL----取值范围为[1/24,365],表的分区时长,单位为天,默认为1,采用一天一分区; -- @PARAM 若为7,则采用一周一分区,若为30,则采用一月一分区; -- @PARAM NUMBER PARTRESERVED----表数据保留时长,单位为天; -- @PARAM NUMBER BACKINTERVAL----取值范围为[3600,7*86400],表数据回迁时的循环步长,即一次回迁多长时间的数据,单位为秒; -- @PARAM VARCHAR2 PARTWEEKDAY-----取值范围为(SUN,MON),PARTINTERVAL为7时起作用,指定一周的起始天为星期日还是星期一; -- @PARAM VARCHAR2 PARTFIELD-------指定的分区时间字段名称 -- @PARAM VARCHAR2 FIELDFORMAT-----指定的分区时间字段的格式 -- @PARAM VARCHAR2 TISPARTITIONED--取值范围为(TRUE,FALSE),指定PARTTABLENAME参数所指定的表是否是分区表,默认为FALSE -- @PARAM VARCHAR2 PARTEXCHANGE----取值范围为(TRUE,FALSE),是否使用交换分区方法实现非分区表的分区化改造,默认为FALSE -- @PARAM 注意:当PARTEXCHANGE参数为TRUE时,TISPARTITIONED参数只能为FALSE, -- @PARAM 即已经分好区的分区表是不能够使用交换分区的方法转换为另一种分区表的; -- @PARAM VARCHAR2 DROPPABLE-------取值范围为(TRUE,FALSE),指定分区完后是否DROP掉分区备份表; 其中参数FIELDFORMAT的取值范围如下: /** * FIELDFORMAT * 0 NUMBER/CHAR MILLISECOND 1300200064000 13BITS * 1 NUMBER/CHAR SECOND 1300200064 10BITS * 2 NUMBER/CHAR YYYYMMDDHH24MISS 20110315224030 * 3 NUMBER/CHAR YYYYMMDDHH24MI 201103152240 * 4 NUMBER/CHAR YYYYMMDDHH24 2011031522 * 5 NUMBER/CHAR YYYYMMDD 20110315 * 6 NUMBER/CHAR YYYYMM 201103 * 7 NUMBER/CHAR YYYY 2011 * 8 CHAR YYYY-MM 2011-03 * 9 CHAR YYYY-MM-DD 2011-03-15 * 10 CHAR YYYY-MM-DD HH24 2011-03-15 22 * 11 CHAR YYYY-MM-DD HH24:MI 2011-03-15 22:40 * 12 CHAR YYYY-MM-DD HH24:MI:SS 2011-03-15 22:40:30 * 13 CHAR YYYY-MM-DD HH24:MI:SSXFF 2011-03-15 22:40:30.765000 * 14 CHAR YYYY"年" 2011年 * 15 CHAR YYYY"年"MM"月" 2011年03月 * 16 CHAR YYYY"年"MM"月"DD"日" 2011年03月15日 * 17 CHAR YYYY"年"MM"月"DD"日" HH24"时" 2011年03月15日 22时 * 18 CHAR YYYY"年"MM"月"DD"日" HH24"时"MI"分" 2011年03月15日 22时40分 * 19 CHAR YYYY"年"MM"月"DD"日" HH24"时"MI"分"SS"秒" 2011年03月15日 22时40分30秒 * 100 DATE 2011-3-15 23:00:01 * 101 TIMESTAMP 15-3月 -11 10.59.30.953000 下午 +08:00 */ -- 第一次分区尽量在数据库闲时操作,这样更能保证分区表的数据一致性; -- 通常使用的现有大表的分区方法:A.使用RENAME分区 B.使用交换分区 C.使用联机定义 只有C方案才能保证数据的完全一致性; -- 但是经过测试发现方案B和C都存在分区过程的不透明性,对EXCEPTION不好控制,另外C方案比较适合手工操作,不适合自动运行; -- B方案比较适合将非分区表中的数据放到分区表中的一个分区中,不符合要求,所以本分区存储过程默认采用A方案; -- 当然,也支持通过新增参数PARTEXCHANGE来控制是否使用B方案;PARTEXCHANGE为TRUE,使用B方案,为FALSE,使用A方案; -- 手动运行示例: 自动对800M以上的非分区大表PM_RAW_B_RESTEST进行分区,一天一分区; -- 手动运行示例: SQL> EXEC AGGRE_PM_PARTITIONF('PM_RAW_B_RESTEST',800,1,10,3600,'SUN','DCTIME','0','FALSE','FALSE','FALSE'); -- 推荐以以上这种方式对单个表进行分区,并将DROPPABLE参数设为'FALSE', -- 这样有什么问题可以跟踪,等完后再可手动将分区备份表DROP掉; -- 注意:分区之前请确保相关表空间足够大。 -- 注意:如果在分区化改造过程中数据回迁之前抛出异常,则手动数据回迁前注意检查分区表有无主键索引。 3.分区维护主过程:AGGRE_PM_PARTITIONM.SQL, 意思是PARTITION MANAGEMENT; 4.创建分区维护JOB -- 对在分区调度表中的已经分区的表进行分区清理以及分区追加等 -- 分区维护操作由该JOB自动完成,该过程不用手动干预。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值