Oracle使用游标进行分批次更新数据的6种方式及速度比对

时间:2021-05-02

1.情景展示

  一共有22w条数据,需要将a表的主键更新至b表的指定字段,如何快速完成更新?

2.解决方案

  声明:

  解决方案不只一种,该文章只介绍快速游标法及代码实现;

  两张表的id和id_card字段都建立了索引。

  方式一:使用隐式游标(更新一次提交1次)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 --快速游标法 begin for temp_cursor in (select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据') loop update virtual_card10 set index_id = temp_cursor.id where id_card = temp_cursor.id_card; commit; --提交 end loop; end;

  执行时间:

  方式二:使用隐式游标(更新1000次提交1次)(推荐使用)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 declare v_count number(10); begin for temp_cursor in (select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据') loop update virtual_card10 set index_id = temp_cursor.id where id_card = temp_cursor.id_card; v_count := v_count + 1; if v_count >= 1000 then commit; --提交 v_count := 0; --重置 end if; end loop; commit; -- 提交所有数据,把这个去掉,可以查看是否是自己想要的效果,再决定是否提交 end;

  执行时间:

  方式三:显式游标+分批次更新(1000条1提交)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 declare v_count number(10); v_index_id primary_index10.id%type; v_id_card primary_index10.id_card%type; cursor temp_cursor is select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据'; begin open temp_cursor; loop fetch temp_cursor into v_index_id, v_id_card; exit when temp_cursor%notfound; update virtual_card10 set index_id = v_index_id where id_card = v_id_card; v_count := v_count + 1; if v_count >= 1000 then commit; --提交 v_count := 0; --重置 end if; end loop; commit; -- 提交所有数据,把这个去掉,可以查看是否是自己想要的效果,再决定是否提交 close temp_cursor; end;

  执行时间:

  10000条1提交,执行时间:

  方式四:显式游标+数组(更新一次提交一次)(使用bulk collect)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 declare type type_index_id is table of primary_index10.id%type; type type_id_card is table of primary_index10.id_card%type; v_index_id type_index_id; v_id_card type_id_card; cursor temp_cursor is select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据'; begin open temp_cursor; loop fetch temp_cursor bulk collect into v_index_id, v_id_card limit 1000; exit when temp_cursor%notfound; for i in v_index_id.first .. v_index_id.last loop update virtual_card10 set index_id = v_index_id(i) where id_card = v_id_card(i); commit; end loop; end loop; close temp_cursor; end;

  执行时间:

  方式五:显式游标+数组(1000条提交一次)(使用bulk collect)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 declare type type_index_id is table of primary_index10.id%type; type type_id_card is table of primary_index10.id_card%type; v_index_id type_index_id; v_id_card type_id_card; cursor temp_cursor is select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据'; begin open temp_cursor; loop fetch temp_cursor bulk collect into v_index_id, v_id_card limit 1000; exit when temp_cursor%notfound; for i in v_index_id.first .. v_index_id.last loop --或者:for i in 1 .. v_index_id.count loop update virtual_card10 set index_id = v_index_id(i) where id_card = v_id_card(i); if i >= v_index_id.last then commit; --提交 end if; end loop; end loop; close temp_cursor; end;

  执行时间:

  方式六:推荐使用(使用bulk collect和forall)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 declare type type_index_id is table of primary_index10.id%type; type type_id_card is table of primary_index10.id_card%type; v_index_id type_index_id; v_id_card type_id_card; cursor temp_cursor is select t2.id, t2.id_card from virtual_card10 t1, primary_index10 t2 where t1.id_card = t2.id_card and t1.remark = '**市****区数据' and t2.remark = '**市****区数据'; begin open temp_cursor; loop fetch temp_cursor bulk collect into v_index_id, v_id_card limit 1000; exit when temp_cursor%notfound; forall i in 1 .. v_index_id.count-- 或者v_index_id.first .. v_index_id.last update virtual_card10 set index_id = v_index_id(i) where id_card = v_id_card(i); commit; --提交 end loop; close temp_cursor; end;

  执行时间:

  从oracle8开始,oracle为pl/sql引入了两个新的数据操纵语言(dml)语句:bulk collect和forall。

  这两个语句在pl/sql内部进行一种数组处理;bulk collect提供对数据的高速检索,forall可大大改进insert、update和delete操作的性能。

  oracle数据库使用这些语句大大减少了pl/sql与sql语句执行引擎的环境切换次数,从而使其性能有了显著提高。

小结:

  数据量小的时候可以用方式二,数据量大的时候推荐使用方式六;

  一定要建索引。

以上就是oracle使用游标进行分批次更新的6种方式及速度比对的详细内容,更多关于oracle 游标的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/Marydon20170307/p/10097243.html

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章