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

单纯的维护产品代号的 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. hdoj 4762 Cut the Cake

    题意很简单就不说了. 解题的关键就是这个公式 answer=n/(m^(n-1)); 要用到大数的乘法.然后java水过. import java.util.*; import java.math.* ...

  2. Kotlin学习快速入门(5)——空安全

    介绍 kotlin中,对象可分为两种类型,可为空的对象和不可为空对象 默认为不可为空对象,代码检测如果发现不可为空对象赋予了null,则会标红报错. 可为空的对象,如果调用了方法,代码检测也会标红报错 ...

  3. 疯子的算法总结(二) STL Ⅰ 算法 ( algorithm )

    写在前面: 为了能够使后续的代码具有高效简洁的特点,在这里讲一下STL,就不用自己写堆,写队列,但是做为ACMer不用学的很全面,我认为够用就好,我只写我用的比较多的. 什么是STL(STl内容): ...

  4. MyBatis 简介与入门

    简介 什么是 MyBatis ? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.My ...

  5. 手摸手,带你用vue实现后台管理权限系统及顶栏三级菜单显示

    手摸手,带你用vue实现后台管理权限系统及顶栏三级菜单显示 效果演示地址 项目demo展示 重要功能总结 权限功能的实现 权限路由思路: 根据用户登录的roles信息与路由中配置的roles信息进行比 ...

  6. Two types of people with high scores of English exams

    I believe that there are two types of people who get high scores in English exams: 1) have high inte ...

  7. java多线程基础(一)--sleep和wait的区别

    sleep和wait的区别有: 1.这两个方法来自不同的类分别是Thread和Object: 2.最主要是sleep方法没有释放锁,而wait方法释放了锁,使得线程可以使用同步控制块或者方法: 3.w ...

  8. python3学习-logging模块

    1.logging模块的使用非常简单,引入模块就可以使用. import logging logging.debug('This is debug message') logging.info('Th ...

  9. 记一次JPA遇到的奇葩错误——本地sql不识别表名的别名

    记一次JPA遇到的奇葩错误——本地sql不识别表名的别名 报错:Unknown column 'our' in 'field list' 起因:需要本地sql查询后,分页返回自定义对象.报错信息如下: ...

  10. wordpress搬家 更换域名

    结论:wordpress网站文件夹是和域名相关联的 wordpress,备份了数据库 然后用另一个新域名新建站,直接从wordpress官网直接下载的网站压缩包,没有用之前的网站文件夹. 然后把原来的 ...