阿里巴巴数据库操作手册 06-加not null字段

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. 普通表如果应用有足够的理由要求回滚,则回滚。

七、 历史故障及教训

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓