首页 > 数据库 >Oracle 游标更新优化

Oracle 游标更新优化

时间:2024-05-17 18:18:32浏览次数:28  
标签:INDEX TEMP T2 游标 CURSOR Oracle 优化 ID CARD

1.情景展示
  一共有22w条数据, 需要将A表的主键更新至B表的指定字段,如何快速完成更新?

2.解决方案
  声明:

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

  两张表的ID和ID_CARD字段都建立了索引。 

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

 

--快速游标法
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
    /* LOOP循环的是TEMP_CURSOR(逐条读取TEMP_CURSOR) */
    UPDATE VIRTUAL_CARD10
       SET INDEX_ID = TEMP_CURSOR.ID
     WHERE ID_CARD = TEMP_CURSOR.ID_CARD;
    COMMIT; --提交
  END LOOP;
END;

  执行时间:25 s

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

 

/* 使用隐式游标进行分批次更新 */
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;
    /* 更新一次,+1 */
    V_COUNT := V_COUNT + 1;
    /* 1000条提交1次 */
    IF V_COUNT >= 1000 THEN
      COMMIT; --提交
      V_COUNT := 0; --重置
    END IF;
  END LOOP;
  COMMIT; -- 提交所有数据,把这个去掉,可以查看是否是自己想要的效果,再决定是否提交
END;

  执行时间:13 s

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

 

/* 使用游标进行分批次更新 */
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;
    /* 更新一次,+1 */
    V_COUNT := V_COUNT + 1;
    /* 1000条提交1次 */
    IF V_COUNT >= 1000 THEN
      COMMIT; --提交
      V_COUNT := 0; --重置
    END IF;
  END LOOP;
  COMMIT; -- 提交所有数据,把这个去掉,可以查看是否是自己想要的效果,再决定是否提交
  CLOSE TEMP_CURSOR;
END;

 

  执行时间:20 s

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

 

/* 使用游标+数组进行更新(更新一次提交一次) */
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
    /* 取得1000行游标数据并放到对应数组中,每次读取1000条数据 */
    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;

  执行时间:25 s

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

 

/* 使用游标+数组进行更新(1000条提交一次) */
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
    /* 取得1000行游标数据并放到对应数组中 */
    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;

  执行时间:13 s

  方式六:推荐使用(使用BULK COLLECT和FORALL)

 

/* 使用游标+数组进行更新(BULK COLLECT和FORALL) */
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
    /* 取得1000行游标数据并放到对应数组中 */
    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;

  执行时间:5 s

从Oracle8开始,oracle为PL/SQL引入了两个新的数据操纵语言(DML)语句:BULK COLLECT和FORALL。

  这两个语句在PL/SQL内部进行一种数组处理;BULK COLLECT提供对数据的高速检索,FORALL可大大改进INSERT、UPDATE和DELETE操作的性能。

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

小结:

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

  一定要建索引。

 

标签:INDEX,TEMP,T2,游标,CURSOR,Oracle,优化,ID,CARD
From: https://www.cnblogs.com/alamZ/p/18198385

相关文章

  • Oracle移动文件
    关闭数据库SQL>shutdownimmediateDatabaseclosed.Databasedismounted.ORACLEinstanceshutdown.移动数据文件,用oracle用户操作[oracle@test~]$mv/u01/app/oracle/oradata/ORCL/system01.dbf/home/oracle/oradata/system01.dbf[oracle@test~]$mv/u01/app/oracl......
  • BOSHIDA AC/DC电源模块的设计与优化
    BOSHIDAAC/DC电源模块的设计与优化AC/DC电源模块是一种将交流电转换为直流电的设备,广泛应用于各种电子设备中。其设计与优化对于提高电源的效率、稳定性以及可靠性非常重要。在设计与优化AC/DC电源模块时,需要考虑以下几个方面。 首先,设计AC/DC电源模块需要选择合适的开关器......
  • DataX将Oracle数据库数据同步到达梦数据库
    1.DataX3.0开源版本,rdbms里面默认是达梦7的驱动,因此,如果像链接达梦8需要替换驱动。需要将达梦8的驱动放在D:\datax\lib、D:\datax\plugin\reader\rdbmsreader\lib和D:\datax\plugin\reader\rdbmswriter\lib下D:\datax\plugin\reader\rdbmsreader\plugin.json和D:\datax\plugin\re......
  • Oracle11g-EXP-00091错误
    环境说明oracle11gwin10问题情况在终端中exp导出数据库时,遇到报错“EXP-00091”,按照网上教程修改NLS_LANG但是没有效果。最终原因在power中设置环境变量NLS_LANG的方法与CMD不一样。备注记录先通过服务端查询编码集select*fromnls_database_parameterstwheret.pa......
  • 使用joinjs绘制流程图(十)-实战-绘制流程图+自定义节点样式(优化)
    问题前面自定义节点的样式坐标位置不对,我们希望自定义节点的坐标和rect元素的位置是一样的效果图代码<template><divclass="app"><divref="myholder"id="paper"></div></div></template><script>import*asjointfrom&......
  • LINQ中使用分页和子查询优化语句
    通过分页加子查询优化后代码:1vardata=fromtestTypeincontext.TestType2joinmodelTypeincontext.ModelTypeontestType.ModelTypeequalsmodelType.IDintomodelJoin3frommodelTypeinmodelJoin.Defau......
  • rm -rf误删Oracle数据库恢复---惜分飞
    联系:手机/微信(+8617813235971)QQ(107644445)标题:rm-rf误删Oracle数据库恢复作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任的权利.]有客户把虚拟化环境中装有oracle数据库的linux操作系统,由于操作失误在/下面执行了rm-rf*,导致所有文件......
  • 从一条巨慢SQL看基于Oracle的SQL优化(重磅彩蛋+PPT)
    转自:从一条巨慢SQL看基于Oracle的SQL优化(重磅彩蛋+PPT)本文根据DBAplus社群第110期线上分享整理而成,文末还有好书送哦~讲师介绍丁俊新炬网络首席性能优化专家SQL审核产品经理DBAplus社群联合发起人、《剑破冰山-Oracle开发艺术》副主编OracleACEA,ITPUB开发版资深版......
  • Centos8系统启动时间优化
    目录前言初始化系统启动阶段firmware(固件)loader(加载器)kernel(内核)initrd(初始RAM磁盘)userspace(用户空间)总结前言因需要,对Centos8操作系统的启动时间进行优化。初始化系统Centos8使用了systemd作为系统和服务管理器。systemd是现代Linux发行版中普遍采用的初始化系统,它......
  • DataX将MySql数据库数据同步到Oracle数据库
    1.下载DataX并解压(本地环境安装有python)DataX/userGuid.mdatmaster·alibaba/DataX(github.com) job文件夹下存放数据同步的json脚本{"job":{"setting":{"speed":{"channel":1}......