首页  |  知识库  |  资源下载  |  在线工具  |  A-Z  •  JAR  •  名词查         

对于在使用Oracle数据库进行系统开发设计时对象命名、设计、开发评审及变更常用的规范六

标签:DML数据修改规范     发布时间:2017-06-26   

上一页

一、引言

1.1         背景及目的

为了避免误操作造成生产故障,本规范要求对生产库所有的人为DML操作都要事先进行准确备份,包括事件组修改批量数据,部署组下发DML脚本等,能够尽快恢复数据。本规范还给出了DBA、开发、运营人员的职责和脚本。

 

1.2         适用范围

Ø  本规范适用于所有的oracle数据库(包括9i10g11g12c及以上)。在后台对数据库人为DML操作都应该遵循本规范,包括但不限于事件响应组数据修改,版本下发DML数据修改,大批量数据修改,后台dmp导入,SQL*Loader等。

 

Ø  只有以下情况不需要遵循本规范:

1)通过正常的前台业务输入产生的DML操作不需要备份。

2)由trigger触发引起的修改不需要备份。

 

1.3         术语和缩略语

序号

术语/缩略语

全称和说明

1

备份表

数据修改时,需要将修改的数据存入一张单独的表中,这张表成为备份表。







 

 

二、DML数据备份修改过程描述

1)    创建备份表。

2)    通过select …. For update的方式将需要修改的数据锁定。

3)    将需要修改的数据整行插入备份表进行备份。

4)    进行实际的数据修改。

5)    进行提交。

6)    如果数据修改还未完成,从步骤2开始下一批次的修改,直至修改全部完成。

7)    备份表改名。目的是避免备份表重名。

 

三、数据修改通用规范

规范1:所有在后台对数据库人为的update和delete的DML操作,都需要进行数据的备份,备份方式为将需要修改或删除的数据整行插入备份表中。

对于insert,则不需要备份。

数据备份的目的一是为了快速回退错误的修改,二是便于对错误的修改进行问题回溯和分析。

采用全表备份是因为,一行记录不同字段之间不是孤立的,回退可能需要整行数据回退。

Insert不需要备份的原因为,按table规范,表上需要加date_created字段,存放该条记录创建的时间,从该字段值上已经能够获取insert的时间,并且回退只需简单的删除该条记录。

 

规范2:必须制定并审核通过数据修改脚本中可以直接调用的package或procedure的白名单,通过这些package或procedure做的数据修改,不用单独进行表备份。白名单之外的package或procedure不能在数据修改脚本中调用。

白名单中需要说明调用的package或procedure的处理内容、涉及到的数据修改内容的风险评估。

 

附: 白名单模板.xlsx

 

规范3:备份和修改的数据必须完全相同。备份的数据仅为本次需要update或delete的记录,修改不涉及的记录不能备份。

 

规范4: 实际的update和delete语句,只能关联备份表进行,不能带有其他的where条件,保证备份的记录和修改的记录完全一致。

 

规范5:为了保证业务在线时备份和修改的正确性,执行备份语句前,要锁定需要修改的记录,备份语句和实际的修改语句在一个事务中。

 

规范6:为了控制事务大小,减少数据修改锁表的时间,以及避免报undo相关错误,每备份和修改5-10万条记录,commit一次。不足5万,作为一个事物处理。超过5万行的数据修改,需要根据业务逻辑拆分为5-10万行左右提交一次。

5-10万条记录一次提交,是经过测试,综合考虑redo、undo、锁表时间、执行时间等指标,得出的结论。

 

规范7:数据修改脚本要实现断点续做,操作由于某种原因出现错误而中断,对于已经处理成功进行过commit的数据,重新执行时不会再进行处理,以便节省处理时间。

 

规范6和规范7,根据业务逻辑进行拆分的方法实现分段提交,以及断点续作,举例如下:

请见: 分段提交示例.sql

 

规范8:无论使用任何版本的Oracle数据库(包括9i、10g、11g、12c及以上),当表的数据修改量(包括但不限于insert/update/delete/imp/impdp/SQL*Loader等)大于等于表的总行数的10%时,需要在操作后立即重新手动收集表及索引的统计信息,详细请参见CBO开发规范》

 

规范9:业务高峰期进行的数据修改,最大可容忍的锁表时间为30秒,根据业务特性的不同,最大可以容忍的时间会低于该值。超过业务所能容忍的锁表时间的数据修改,需要在非业务高峰期进行。

    测试数据,供参考:50万修改,锁表时间约2.5分钟。

 

规范10:一次版本或DML修改中,如果DML(Update修改行数+3*delete修改行数+6*insert行数)超过50万,则认为是大批量数据修改操作,除了需要遵守上述规范外,还需要遵守“大批量数据修改规范”,如下第六章节。

规范11:如果发现数据修改错误,回退需要谨慎,需要评估是否所有数据都可以回退,是否可以直接用备份数据覆盖当前数据,是否需要根据当前数据和备份数据计算出新的值等等内容,不能直接简单地用备份数据进行恢复。

规范12在进行DML操作时,必须采用带绑定变量的SQL执行。避免由于过多的硬解析造成数据库异常。建议参考如下书写方案:

       先定义变量,然后在每次SQL语句执行前对变量进行赋值,SQL语句使用绑定变量执行。例如:

       variable B1 varchar2(20);

       variable B2 varchar2(20);

       variable B3 number;

       exec :B1 := 'A1';

       exec :B2 := '2015-09-01 12:00:00';

       exec :B3 :=1;

       update aa set r2=to_date(:B2,'yyyy-mm-dd hh24:mi:ss'),r3=:B3 where r1=:B1;

       exec :B1 := 'A2';

       exec :B2 := '2015-09-02 12:00:00';

       exec :B3 :=2;

       update aa set r2=to_date(:B2,'yyyy-mm-dd hh24:mi:ss'),r3=:B3 where r1=:B1;

四、数据备份修改环境配置

为了按规范实现数据备份,备份修改在数据库中需要进行环境配置。脚本如附件:

配置脚本.rar

 

对附件脚本说明如下:

 

Ø  建立dmlbak用户和该用户的默认表空间(11g前)dmlbakdata或(11g及以上)users。备份相关配置脚本、JOB以及备份表均建立在该用户下。

Ø  创建了备份表查询角色r_dmlbak_qry,所有备份表均需授权给该角色。

 

Ø  建立备份信息表bktb_info,保存了存储备份表名、备份表名、源表属主、源表名、版本或者事件号和备份时间。存储备份表名是改名后存储在数据库的表名,以后查找或者恢复的时候将用到这个表名。备份表名是编写脚本过程中由开发命名的。源表名是DML操作的对象。版本或者事件号是本次DML脚本所属的版本或事件编号。备份时间是备份信息记录到信息表的时间。

 

Ø  建立create_bak_table_pkg包。用来创建备份表、重命名备份表。

 

Ø  建立删除备份表和清理备份信息表的JOB,根据备份信息表中的备份时间字段,每天清理一次,每次删除90天前的备份表,并将删除时间计入备份信息表

 

Ø  DML执行用户需要申请create_bak_table_pkg的执行权限。

 

如果需要查询所有备份表信息的用户,请申请角色r_dmlbak_qry的权限。

 

 

五、开发提供脚本规范

为了符合上面规范,DBA制作了数据备份修改模板,如附件:

备份修改模板.rar

 

说明如下:

5.1备份修改脚本:

1)        备份表的结构如下:bak_rowid(源表中的rowid值)+源表中所有字段+date_dml_flag (标志位,timestamp类型)

同一个SR中针对一张表的同一类型的修改,创建一张备份表。

备份表date_dml_flag记录实际修改的时间,以便对同一张表进行多次修改时,追溯修改历史以及数据变化顺序。

 

2)备份表命名严格按照规范:

update问题号或SR需求号+源表名(或者表名缩写)+_bu

delete问题号或SR需求号+源表名(或者表名缩写)+_bd

同一个问题或者SR中,对同一张表的数据update,必须合并到一起处理;delete也必须合并到一起处理。

 

 

3 执行脚本的用户请确认是否有源表的DML权限和create_bak_table_pkg的执行权限,没有权限请申请DBA协助。

 

4)备份脚本一定要在修改脚本之前执行。 执行create_bak_table 创建备份表:DMLBAK.create_bak_table_pkg.create_bak_table('[v_user]','[v_source_owner]','[v_source_tname]','[v_backup_tname]');

备份表都是建在dmlbak用户下的,在执行create_bak_table时会给v_user授予新建备份表的操作权限,请在填写该参数的时候明确脚本执行用户(例如DML执行用户是edsop,那么备份修改和恢复脚本的执行用户都应该是edsop,而且v_user也应该填edsop)。

v_source_ownerv_source_tname是源表属主和源表名,备份表是根据源表名创建的,如果该处出错,备份表将创建有误。

v_backup_tname是开发自己命名备份表名称,后续脚本中都要用到该名称,请在执行改名过程前保证该名称的唯一。

 

5)完成备份表的创建后,将需要修改的记录用select .. for update锁定,待这个记录修改完后进行commit释放。如果数据量大于50万条时,要分批锁定(50万条一次)。

 

 

6updatedelete操作都进行整行数据的备份,insert插入备份表。备份表中包括了源表的所有字段和rowid。支持含有LONGLOB字段的源表。

 

7)注意DMLupdate\delete)的时候,where条件只能是关联备份表,不能带其他逻辑条件。请严格遵守。这样才能保证修改的数据都得到了备份,备份的数据都修改了,防止多改、漏改、错改的情况。

 

8) 编写脚本的时候,请注意在备份表前面带上dmlbak属主。

 

9)脚本中updatedelete源表,通过rowid关联备份表进行。这里使用ROWID已通过例外申请,可以使用。其他情况情况遵照相关规范,仍然禁止使用ROWID

 

5.2改名脚本:

1DML结束后,一定要执行DMLBAK.create_bak_table_pkg.pc_bktb_rename过程,该过程用来重新命名备份表,并把规范后的存储的备份表名、原始的备份表名、源表名和版本CQ号(或ITSM事件号)等记入bktb_info表。这样做是为了保持备份脚本原貌,并避免备份表命名冲突的问题。

 

5.3恢复脚本:

1)              根据源表属主、源表名、版本和事件号从dmlbak.bktb_info中可以查到相应的记录,并结合之前命名的备份表名判断改名后的存储表名。

 

2)              查询备份表信息的时候,注意要带上dmlbak属主。

 

select * from dmlbak.bktb_info where

rs_version=upper('[v_rs_version]') and      -- [v_rs_version]替换成SR

           source_owner=upper('[v_source_owner]') and  -- [v_source_owner]替换成源表属主

source_tname=upper('[v_source_tname]');     -- [v_source_tname]替换成源表名

 

3)恢复时可以根据备份表中的信息有选择进行恢复。

 

 

六、大批量数据修改规范

规范13所有大批量数据修改需要纳入版本,并在版本移交部署时明确说明有大批量操作。

 

规范14(针对开发人员)对于版本中存在大批量数据修改,如果此次大批量修改的数据量大于等于原有数据量的10%,则开发需要在版本前提交《生产数据处理脚本提供和验证》流程,由DBA保证提供统计信息收集的脚本;进行统计信息收集后,是否需要做性能影响分析,由开发测试管理分组的DBA判断并提供脚本。

 

规范15(针对开发人员)对于版本中存在大批量数据修改,需要评估是否影响到关联系统,是否会触发关联系统大批量,如果关联系统也触发大批量操作,关联系统方也要遵循大批量规范进行大批量通知和申请大批量监控等。

 

规范16(针对开发人员)开发人员在版本移交前需要提前计算本次大批量操作的空间需求,计算方法如附件:

大批量数据修改操作空间预估方法.doc

 

然后提交“大批量数据修改协助评估”给运维DBA,评估是否需要扩容。如果需要扩容,在版本封版之前,需要按打包服务流程完成扩容。

评估邮件需要填写以下内容:

表属主

表名

需要的空间(M)(注包括表本身、索引和lob的空间)
















 

 

规范17(针对部署人员)对于版本中有大批量数据修改的内容,部署人员在版本发布生产之前需要通过request提交《大批量数据修改监控申请》给数据库基础运维DBA

  部署同事在request中需说明此大批量是否经过测试,以及在测试环境执行的时长,以及undo使用大小。查询undoredo占用大小的sql如下:

--查询undo使用的大小,单位M,按使用大小排序

 

select

 (a.USED_UBLK * c.value /1024/1024) "undo size M",b.SID,b.SERIAL#, b.USERNAME

from v$transaction a,v$session b ,v$parameter c

where a.SES_ADDR=b.SADDR and c.name ='db_block_size' order by 1 desc;     

 

 

 

--查询整个实例的redo的大小,需要采集批量开始前。结束后,采集2次。

--redo大小为LOGSIZE *BEGIN_SEQ - END_SEQ),单位M

 

--开始前采集

select sequence# "BEGIN_SEQ" from v$log where status='CURRENT';

 

--结束后采集

select sequence# "END_SEQ" from v$log where status='CURRENT';

 

select trunc(avg(bytes/1024/1024)) "LOGSIZE"  from v$log ;

规范18(针对部署人员)在RAC数据库上执行大批量数据操作,同一次的操作必须指定连接到同一个实例去运行,避免实例之间产生大量的数据交换而降低数据库性能。

例如:

Cif2为RAC数据库,有两个实例:cif2r1和cif2r2,当在cif2中执行大批量时,连接数据库需要如下书写:

SQL> connect deployop@cif2r1     --指明连接第一个实例

  SQL> connect deployop@cif2r2     --指明连接第二个实例

如下书写是不正确的:

  SQL> connect deployop@cif2       --未指明具体的实例,Oracle可能会连到不同的实例上。

 

规范19(针对DBA)运维DBA接到大批量数据修改申请后,在大批量数据修改执行期间,需要监控数据库归档空间使用率、数据库中session wait情况、UNDO使用情况、执行大批量操作的sessionwait event,并进行相关的异常处理。

 

规范20:对于没有告知DBA的大批量量操作,如果产生log卷的告警,按以下规范进行处理。

(1)实名用户的处理原则:

当实名用户被监控到生成大量redo log,可能会影响生产可用性的时候,不区分时间,直接Kill。由运营对实名用户进行宣导,由于产生大量log而被Kill产生的数据异常或其他后果由实名用户所有人承担。

 

(2)对于非实名用户(应用用户、应用部署用户)的处理原则:

报警及处理:

数据库log卷由于大批量修改造成使用率高,一方面DBA进行压缩Log,转移log的动作;另一方面DBA找到产生大量redo的session,同时邮件提供报警的Session信息和当时在执行的sql,由运营决定是否可以Kill Session来解决问题。

 

规范21:关于job定时作业补做的说明

1Job失败补做作为应用的大批量数据处理,不作为IT内部的大批量数据处理。

2Job失败如果需要在服务窗口补做,由应用服务组牵头确定补做时间,并发job失败补做的大批量数据处理通知到IT服务和计划行事历。

3Job失败在服务窗口时间的补做,必须邮件通知到DBA运维组值班人员。运营和DBA必须明确指定运营的操作人员和DBA的监控配合人员。

4)非服务窗口时间(IT维护时间窗口)补做,不需要通知。


  • ◆ 相关内容