生产上要修改某个产品的产品代号, 而我们系统是以产品为中心的, 牵一发而动全身, 涉及表几乎覆盖全部, 有些表数据量是相当大的, 达到千万, 亿级别.

单纯的维护产品代号的 SQL 是不难的, 但是性能是最大的问题, 最后采用了 rowid+forall分批更新策略.

细节涉及:

游标(rowid)

dbms_sql.Urowid_Table

(异常声明;)

fetch v_rowid_cursor bulk collect into v_rowid_table limit v_once_commit; ...

forall i in 1 .. v_rowid_table.count save exceptions ...

完整代码:

PL/SQL存储过程分批更新↓

 --rowid+forall批量更新
declare
v_total_count integer default 500000; --待更新目标记录总计
v_once_commit integer default 10000; --单次提交量
v_pre_prod_code char(8) := '';
v_new_prod_code char(8) := '9031000X';
v_dml_name varchar2(100) := 'update tb_cust_vol_list 20181215 01';
v_suc_count integer := 0; --成功提交计数
v_err_count integer := 0; --失败记录数
v_curr_batch integer := 0; --当前提交批次
v_start_time date := sysdate; --开始时间
--待更新目标记录rowids
cursor v_rowid_cursor is
select rowid from tb_cust_vol_list
where prod_code = v_pre_prod_code
order by rowid; --rowid排序,提高效率
v_rowid_table dbms_sql.Uv_rowid_table; --临时单次rowid放置表
v_error exception; --异常声明
pragma exception_init(v_error, -24381); --指定ora-错误码 begin
--操作日志
insert into tb_dml_log values (
v_dml_name,
v_total_count,
v_once_commit,
v_start_time,
v_start_time,
0, 0, 0, 0, 0
);
commit; open v_rowid_cursor; --打开rowids游标
loop
exit when v_rowid_cursor%notfound;
--临时rowids表
fetch v_rowid_cursor bulk collect into v_rowid_table limit v_once_commit;
exit when v_rowid_table.count = 0; begin
forall i in 1 .. v_rowid_table.count save exceptions
--rowid定位行更新
update tb_cust_vol_list set prod_code=v_new_prod_code where rowid=v_rowid_table(i);
exception
when v_error then --目标异常
dbms_output.put_line('ora-24381, error in array DML !');
dbms_output.put_line('exception count: ' || sql%bulk_exceptions.count);
v_err_count := v_err_count + sql%bulk_exceptions.count;
when others then
dbms_output.put_line('ora-XXX error occurred !');
dbms_output.put_line('exception count: ' || sql%bulk_exceptions.count);
v_err_count := v_err_count + sql%bulk_exceptions.count;
end; v_suc_count := v_suc_count + v_rowid_table.count;
v_curr_batch := v_curr_batch + 1;
--更新log
update tb_dml_log a set
a.curr_time=sysdate,
a.curr_cost=ceil((sysdate-v_start_time)*24*60*60),
a.curr_batch=v_curr_batch,
a.process=v_suc_count/a.total_count,
a.suc_count=v_suc_count,
a.err_count=v_err_count
where a.dml_name=v_dml_name;
commit; end loop; dbms_output.put_line('total error count: ' || v_err_count);
end;

有帮助的博客:
https://blog.csdn.net/leinuo180/article/details/23344647

其他考虑:

如果有的表目标数据实在太大, 就算上述优化依然很费时间, 可将此表的目标数据拆分, 比如按月, 按编号.. 分几个脚本, 维护时并行执行.

查询语句获取所有目标数据的 rowid 时, 如果占比很大(索引空间大), 可以尝试禁用索引查询, 使用全表并行查(网上看到的,本人还未尝试).

超大表要注意索引空间的维护.

@20190126更新

批量数据更新方式

1)表重建

即先新建复制表(create 新表(...) as select ... from 旧表 where ...),然后删除旧表(drop),最后修改表名(rename 新表名 to 旧表名),最后恢复表结构(约束,索引等)。

2)rowid+forall PL/SQL存储过程更新

即上面的办法

3)JDBC程序分批更新

优点是DB无关性,性能也不慢,只是数据量太大(千万级)时,力不从心。

Oracle大量数据更新策略的更多相关文章

  1. ASP.NET Cache 实现依赖Oracle的缓存策略

    ASP.NET 中的缓存提供了对SQL依赖项的支持,也就是说当SQL SERVER数据库中的表或行中的数据被更改后,缓存中的页面就失效,否则,页面输出可一直保留在缓存当中.这确实为程序员提供了方便.但 ...

  2. Oracle RMAN备份策略

    建立增量备份:如果数据库运行于不归档模式下,只能在数据库干净关闭的情况下 ( 以 normal .immediate . transactional 方式关闭 ) 才能进行一致性的增量备份,如果数据库 ...

  3. Oracle数据库备份策略:全备与增量备份

    一.RMAN全备份 在数据量比较小.或者数据库服务器性能很强大的情况下,可以每天进行一次全备份. 全被策略如下 1.crontab定时任务,避开业务繁忙时段 ##################### ...

  4. Web系统与自控系统数据通讯架构 之 OPC DA DataChangeEventHandler 非热点数据更新策略 ,

    在使用OPC 采集 工控数据时,在DA模式下.采集数据通常用到 DataChangeEventHandler这个事件.但有时会遇到一些问题,就是当数据不变化时时不会触发 DataChange 这个事件 ...

  5. Oracle的Recyclebin策略

    1.从oracle10g开始删除数据库表的时候并不是真正删除,而是放到了recyclebin中,这个过程类似 windows里面删除的文件会被临时放到回收站中. 2.删除的表系统会自动给他重命名就是你 ...

  6. Oracle备份及备份策略

    第二章. 了解备份的重要性 可以说,从计算机系统出世的那天起,就有了备份这个概念,计算机以其强大的速度处理能力,取代了很多人为的工作,但是,往往很多时候,它又是那么弱不禁风,主板上的芯片.主板电路.内 ...

  7. oracle与DB2

    1.体系结构,DB2的实例和数据库分开的做法,我个人还是比较喜欢的,因为实例可以创建多个,数据库的恢复直接恢复到实例下就可以了,相对ORACLE简单多了. 2.管理工具,DB2的管理工具做得太简陋了, ...

  8. DB2和Oracle区别

    转 http://blog.chinaunix.net/uid-7374279-id-2057574.html 写在前面:今天客户来访(日本人),问我DB2和Oracle区别.因为不是DBA(勉强的理 ...

  9. 微軟将从 .NET 4 以后的版本弃用 System.Data.OracleClient 以及Oracle 的各种连接方法

    这是微软官方 ADO.NET Team Blog 去年就公布的消息: http://blogs.msdn.com/adonet/archive/2009/06/15/system-data-oracl ...

随机推荐

  1. jsp数据交互(一).3

    引入的文件如果是jsp则应定义为***.jspf文件,如果其他文件可定义为***.inc文件,即include file. jsp:include是既可以静态包含又可以动态包含,用jsp:includ ...

  2. 0 MapReduce实现Reduce Side Join操作

    一.准备两张表以及对应的数据 (1)m_ys_lab_jointest_a(以下简称表A) 建表语句: create table if not exists m_ys_lab_jointest_a ( ...

  3. MYSQL 时间轴数据 获取同一天数据的前3条

    创建表数据 CREATE TABLE `praise_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `pic_id` va ...

  4. c#小灶——初识c#

    提到c#,就不得不说.net,.net是微软开发的一个平台,简单来说,在这个平台上,可以编写.运行程序.可能很多人觉得这个平台离我们很遥远,其实不然,这个平台就一直在我们的windows操作系统里,默 ...

  5. mule优缺点和MEL

    优点1.开源 https://github.com/mulesoft/mule2.丰富的connector ,可以通过不同的形式来连接各个系统JMS.Web Service.JDBC.HTTP等3.c ...

  6. 面向对象---prototype、__proto__、实例化对象三者之间的关系

    1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...

  7. 同时启动多个tomcat,端口修改

    所用Tomcat服务器都为zip 版,非安装版.以 tomcat8 为例: 安装第二个Tomcat完成后,打开 tomcat/conf/server.xml 文件,查找以下三处: 1. 修改http访 ...

  8. 【Java例题】7.1 线程题1-时间显示线程

    1.时间显示线程.设计一个示线程子类,每秒钟显示一次当前时间:然后编写主类,在主函数中定义一个线程对象,并启动这个线程 package chapter7; import java.text.Simpl ...

  9. java8(一)Lambda表达式

    其实很久前已经学习过了Lambda表达式,但是学习后没有多少使用的机会,久而久之也就忘记(惭愧).最近新的项目用的jdk8所以准备再学习一次,写下文章也是为了记录,方便以后再忘的时候,不用到处找资料( ...

  10. String——字符串

    首先看一下string的一部分源码吧 public final class String private final char value[]; 我们暂且只看这两行, 第一行String被final修 ...