V1.0
Revision |
Author/Modifier | Comments | |
No. |
Date |
||
1.0 | 2012/2/14 | 梅庆 | 初稿 |
一、 目的
阐述表变更的风险及其步骤,降低对应用的影响和避免故障。
二、 适用范围
l 所有在使用的表的加not null字段,但核心表(并发访问高的大表不允许加not null)。
三、 风险评估
l 新增字段的类型、长度(精度)是否合适
解决方法:跟应用明确加字段和改字段的风险,确认新增字段类型正确、长度(精度)合适。是否有默认值?以及跟应用明确老数据是否要订正?如何订正?
l 新增字段的非空属性、默认值以及老数据问题。
新增字段是NOT NULL的,则一定要有默认值,否则老应用的insert代码可能报错。
表如果存在老数据,带上默认值的时候会导致oracle去订正老的数据行的新增列。如果老数据非常多,表的并发访问高,很有可能导致大面积的阻塞等待以及产生大事务,甚至有可能导致undo耗尽。倘若回滚,还会因为回滚产生的并发会话导致load飙升。
解决方法:先不带not null不带默认值加上列,再更改列默认值,再批量订正老数据,然后再加上not null属性。
如果是大表,并且并发访问很高的表,则新增列不允许为NOT NULL,以简化后面变更步骤,降低风险!
l 新增字段导致依赖对象失效、sql游标失效问题。
表的DML并发很高的时候,如果表上面还有依赖对象,新增字段会导致依赖对象失效。默认访问这些依赖对象的会话(如DML会话,或者应用调存储过程等)会尝试去自动编译这个依赖对象(9i所有会话都会尝试去编译,10g以后只有一个会话去主动编译,其他等待),此时很可能会出现大面积的library cache pin。应用会话的连接时间会加长,进而导致出现后续应用报不能取得连接池错误。应用服务器load由此飙升。
表新增字段也会导致跟该表有关的SQL的游标失效,如果SQL的并发很高(查询SQL或者DML SQL),失效后SQL会重新解析,此时也可能会出现大量的library cache pin & library cache lock。
解决方法:选择在业务低峰期发布,同时在数据库级别开启trigger禁用客户端程序自动编译功能,字段加完后再禁用该trigger。
l 表的依赖对象是否要相应调整。
表上面的依赖对象如果有存储过程或触发器等,逻辑是否需要相应调整。
l 是否涉及到同步。
同步中的表需要两地都要变更。涉及到erosa的要更新一下数据字典。Erosa需要重启一下。
l 是否要通知其他关联的部门。如DW, ASC或CRM等等。
有些表很多部门都用,需要沟通约定时间一起变更。如果有同步方案,同步方案的变更也要考虑。
l 表结构变更后应用需要重启。
应用端缓存的表结构跟实际结构有冲突报错。
四、 操作流程
1. 准备工作
a) 该表的数据量以及大小,以及数据变更量(按日/时/分/秒等)
b) 该表的并发访问数,以及频率最高的几种sql的访问方式
2. 执行过程
以表T1 加字段 col2为例。T1的数据量非常大,访问频率很高。
a) 在sysdba下开启trigger禁用客户端自动编译功能。(可选)
Alter trigger SYS.ddl_trigger_for_database enable;
b) 变更字段
以下加字段同编译失效对象连着执行。编译时先编译trigger再编译存储过程或package等
@conn zzzzzz/aaa
Alter table t1 add col2 varchar2(20);
–如果需要默认值,加上默认值
Alter table t1 modify col2 default ‘Y’;
Alter trigger trg_t1_search compile;
@conn retl/rrr
Alter trigger trg_t1_sync compile;
@conn bopsretl/bbb
Alter trigger trg_t1_sync compile;
@conn zzzzzz/aaa
Alter procedure sp_test compile;
另开一个窗口,在admin用户下查看当前失效对象
@dbcheck
c) 禁用ddl trigger
Alter trigger SYS.ddl_trigger_for_database disable;
d) 老数据订正
–数据订正存储过程
Create or replace procedure sp_dml0214
As
Cursor c1 is select rowed rid, id, col2 from t1 where col2 is null;
V_cnt number := 0;
Begin
For rec_c1 in c1 loop
V_cnt := v_cnt + 1;
Update t1 set col2=’Y’ where rowid = rec_c1.rid and id=rec_c1.id;
If mod(v_cnt,500)=0 then
Commit;
End if;
End loop;
Commit;
End;
/
Exec sp_dml0214;
另开一个窗口,用@sqlinfo脚本查看订正进度
e) 订正完后加上NOT NULL属性(核心表不要做了),风险和步骤详情参见文档:4.增加、删除唯一约束
Alter table t1 modify col2 not null;
f) 表涉及到同步后,再多个节点变更,erosa是否重启取决于erosa版本。
–更新erosa数据字典
./getDict.sh
–erosa重启
./erctl stop
./erctl start
3. 验证方案
a) 验证sys下的trigger已经禁用
Select owner,trigger_name,status from dba_triggers where owner in (‘SYS’) and trigger_name=upper(’ ddl_trigger_for_database’);
b) 验证结构正确
Desc zzzzzz.t1
c) 验证无失效依赖对象
@dbcheck
d) 跟测试库比对。
五、 核心对象风险
核心对象风险指的是业务上重要的表,并且数据量很大或表大小很大或并发访问数很高时,变更的潜在风险。前面已经阐述。
六、 回退方案
1. 大表的新增字段不允许回滚。因为回滚即删掉字段,会导致锁表,持续时间很长进而导致一序列的严重问题。
2. 普通表的新增字段如果是发布失败,后续还会有二次发布,也不考虑回滚。或者只是将not null属性拿掉,下次发布再加上。
3. 普通表如果应用有足够的理由要求回滚,则回滚。
七、 历史故障及教训
略