Oracle学习:批量SQL实例分析与比较

2011年12月14日17:23 来源:博客 作者:Snowtoday 编辑:苏巧红 评论:0条

  【IT168技术】PL/SQL引入过程化语言的相应元素,比如条件分支或者循环,不过,SQL本身仍然作为主体嵌套于其中,由于需要SQL引擎才能执行SQL命令,对于PL/SQL程序,往往存在许多PL/SQL引擎 - SQL引擎之间的交互,过多这样的交互会对性能产生负面影响。

  相关阅读:

  Oracle学习:结构化查询实例演示与解析

  Oracle在PL/SQL中引入了BULK SQL,用于尽量减少PL/SQL – SQL引擎之间的交互,以期提高性能。具体而言,Oracle BULK SQL包括FORALL语句、BULK COLLECT子句。前者将多条语句(通常是DML)一次性发送给SQL引擎;后者将SQL引擎所获得的结果一次性返回给PL/SQL引擎。

  FORALL

  下面的两个例子对比了FORALL与FOR循环之间的区别:

SQL> create table t_bulk as select * from employees;
SQL> desc t_bulk;
Name           Type         Nullable Default Comments
-------------- ------------ -------- ------- --------
EMPLOYEE_ID    NUMBER(6)    Y                        
FIRST_NAME     VARCHAR2(20) Y                        
LAST_NAME      VARCHAR2(25)                          
EMAIL          VARCHAR2(25)                          
PHONE_NUMBER   VARCHAR2(20) Y                        
HIRE_DATE      DATE                                  
JOB_ID         VARCHAR2(10)                          
SALARY         NUMBER(8,2)  Y                        
COMMISSION_PCT NUMBER(2,2)  Y                        
MANAGER_ID     NUMBER(6)    Y                        
DEPARTMENT_ID  NUMBER(4)    Y

DECLARE
  TYPE NumList IS VARRAY(20) OF NUMBER;
  depts NumList := NumList(10, 30, 70);  
BEGIN
  FOR i IN depts.FIRST..depts.LAST LOOP
    DELETE FROM t_bulk
    WHERE department_id = depts(i);
  END LOOP;
END;

DECLARE
  TYPE NumList IS VARRAY(20) OF NUMBER;
  depts NumList := NumList(10, 30, 70);  -- department numbers
BEGIN
  FORALL i IN depts.FIRST..depts.LAST
    DELETE FROM t_bulk
    WHERE department_id = depts(i);
END;

  虽然从内部执行机制上来说,两个循环有很大的区别,但从语法上来说,还是非常类似的。不过有一个小细节需要注意,就是FORALL语句并没有对应的END语句。

  我们再来看看使用FORALL的情况下对异常的处理:

CREATE TABLE t_bulk2(f1 NUMBER(3));
DECLARE
  TYPE type1 IS TABLE OF NUMBER;
  v type1:=type1(1, 2, 3000, 4, 5, 6, 77777, 8, 9, 10001);
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE t_bulk2';
  --
  FORALL idx IN v.FIRST..v.LAST
    INSERT INTO t_bulk2 VALUES(v(idx));
  --
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
ORA-01438: 值大于为此列指定的允许精度
PL/SQL procedure successfully completed
SQL> SELECT * FROM t_bulk2;
  F1
----
   1
   2

  Oracle 9i中引入了SAVE EXCEPTIONS语法及与之对应的“ORA-24381: error(s) in array DML”异常,使用它们,我们可以跳过FORALL中出现异常的语句,并将异常保存在SQL%BULK_EXCEPTIONSP这个集合中:

DECLARE
  TYPE type1 IS TABLE OF NUMBER;
  v type1:=type1(1, 2, 3000, 4, 5, 6, 77777, 8, 9, 10001);
  --
  BULK_ERROR EXCEPTION;
  PRAGMA EXCEPTION_INIT(BULK_ERROR, -24381);
BEGIN
  EXECUTE IMMEDIATE 'TRUNCATE TABLE t_bulk2';
  --
  FORALL idx IN v.FIRST..v.LAST SAVE EXCEPTIONS
    INSERT INTO t_bulk2 VALUES(v(idx));
  --
EXCEPTION
  WHEN BULK_ERROR THEN
    FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP
      DBMS_OUTPUT.PUT_LINE(SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)||', Statement: #'||SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
    END LOOP;
  WHEN OTHERS THEN
    NULL;
END;
ORA-01438: 值大于为此列指定的允许精度, Statement: #3
ORA-01438: 值大于为此列指定的允许精度, Statement: #7
ORA-01438: 值大于为此列指定的允许精度, Statement: #10
PL/SQL procedure successfully completed
SQL> SELECT * FROM t_bulk2;
  F1
----
   1
   2
   4
   5
   6
   8
   9

  (注意使用ERROR_CODE时要加上负号。)

  下面介绍如何获取第一条语句所影响的行数,这需要使用SQL%BULK_ROWCOUNT:

create table t_bulk3(fid number);
insert into t_bulk3 values(1);
insert into t_bulk3 values(2);
insert into t_bulk3 values(2);
insert into t_bulk3 values(3);
insert into t_bulk3 values(3);
insert into t_bulk3 values(3);
insert into t_bulk3 values(3);
DECLARE
  TYPE type1 IS TABLE OF NUMBER;
  v type1:=type1(1, 2, 3, 4);
  --
  BULK_ERROR EXCEPTION;
  PRAGMA EXCEPTION_INIT(BULK_ERROR, -24381);
BEGIN
  FORALL idx IN v.FIRST..v.LAST SAVE EXCEPTIONS
    DELETE FROM t_bulk3 WHERE fid=v(idx);
  --
  FOR idx IN v.FIRST..v.LAST LOOP
    DBMS_OUTPUT.PUT_LINE('Statement: #'||idx||', '||SQL%BULK_ROWCOUNT(idx)||' rows were impacted.');
  END LOOP;
  --
EXCEPTION
  WHEN BULK_ERROR THEN
    FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP
      DBMS_OUTPUT.PUT_LINE(SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)||', Statement: #'||SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
    END LOOP;
  WHEN OTHERS THEN
    NULL;
END;
Statement: #1, 1 rows were impacted.
Statement: #2, 2 rows were impacted.
Statement: #3, 4 rows were impacted.
Statement: #4, 0 rows were impacted.
PL/SQL procedure successfully completed

  BULK COLLECT

  假设有一条SQL查询,返回的记录中包含5行,那么如果在PL/SQL中执行此查询,会有5次的PL/SQL – SQL交互,如果使用BULK COLLECT,可以降低到1次。

  BULK COLLECT子句可以出现在以下语句中:

  SELECT INTO

  FETCH

  RETURNING INTO

create table t_bulk4(fid number, fval varchar2(20));
insert into t_bulk4 values(1,'abc');
insert into t_bulk4 values(2,'def');
insert into t_bulk4 values(3,'xyz');
insert into t_bulk4 values(4,'xxx');
insert into t_bulk4 values(5,'123');
commit;
DECLARE
  TYPE type1 IS TABLE OF t_bulk4%ROWTYPE;
  v type1;
BEGIN
  SELECT * BULK COLLECT INTO v FROM t_bulk4;
  --
  FOR i IN 1..v.COUNT LOOP
    DBMS_OUTPUT.PUT_LINE(v(i).fid||' '||v(i).fval);
  END LOOP;
END;
1 abc
2 def
3 xyz
4 xxx
5 123
PL/SQL procedure successfully completed

  另一个INDEX BY集合的示例(实际上使用跟上例一样的FOR循环也可以):

DECLARE
  TYPE type1 IS TABLE OF t_bulk4%ROWTYPE INDEX BY PLS_INTEGER;
  v type1;
  idx PLS_INTEGER;
BEGIN
  SELECT * BULK COLLECT INTO v FROM t_bulk4;
  --
  idx:=v.FIRST;
  WHILE(idx IS NOT NULL) LOOP
    DBMS_OUTPUT.PUT_LINE(v(idx).fid||' '||v(idx).fval);
    idx := v.NEXT(idx);
  END LOOP;
END;

  FETCH cursor BULK COLLECT INTO的使用与上述例子都类似,不多写了。

  关于RETURNING INTO + BULK COLLECT,我们来一个综合的例子:

create table t_bulk5(fid number);
DECLARE
  TYPE type1 IS TABLE OF NUMBER;
  v type1:=type1(1, 2, 3, 5);
  --
  TYPE type2 IS TABLE OF t_bulk5.fid%TYPE;
  v2 type2;
BEGIN
  FORALL idx IN v.FIRST..v.LAST
    INSERT INTO t_bulk5 VALUES(v(idx)) RETURNING fid BULK COLLECT INTO v2;
  --
  DBMS_OUTPUT.PUT_LINE(v2.COUNT);
END;
4
PL/SQL procedure successfully completed

  顺便比较一下使用FOR循环时是什么结果:

DECLARE
  TYPE type1 IS TABLE OF NUMBER;
  v type1:=type1(1, 2, 3, 5);
  --
  TYPE type2 IS TABLE OF t_bulk5.fid%TYPE;
  v2 type2;
BEGIN
  FOR idx IN v.FIRST..v.LAST LOOP
    INSERT INTO t_bulk5 VALUES(v(idx)) RETURNING fid BULK COLLECT INTO v2;
  END LOOP;
  --
  DBMS_OUTPUT.PUT_LINE(v2.COUNT);
END;
1
PL/SQL procedure successfully completed

  这实际上也好理解,因为上面的INSERT语句每次影响的只有一行,所以第二例中,保留的是循环中最后一次执行的INSERT所影响的行数,当然是1;而由于FORALL语句会将所有语句一次性提交到数据库,这也使得我们可以使用RETURNING INTO + BULK COLLECT获取所有插入

转载于:https://www.cnblogs.com/Mayvar/archive/2012/02/01/wanghonghua_201202010821.html

ORACLE 批量实例分析相关推荐

  1. oracle 错误实例分析(ORA-01078)

    01,问题描述 心血来潮想看一下启动数据库的alert log.然后把数据库给关闭了,同时也在监听日志文件    下面可谓是详细的描述了整个关机过程,也看到了无数的error 1 [root@node ...

  2. python查询oracle数据库_python针对Oracle常见查询操作实例分析

    本文实例讲述了python针对Oracle常见查询操作.分享给大家供大家参考,具体如下: 1.子查询(难): 当进行查询的时候,发现需要的数据信息不明确,需要先通过另一个查询得到, 此查询称为子查询: ...

  3. 详解Oracle AWR运行日志分析工具

    在Oracle数据库学习和使用中,遇到性能问题,首要的步骤就是导出AWR分析报告,AWR是Oracle的一个脚本工具,通过周期性快照记录下当时的所有运行数据,数据库管理员可以导出其中一部分数据进行分析 ...

  4. awr报告 解读_【数据库】解读Oracle AWR性能分析报告

    1.什么是AWR? AWR (Automatic Workload Repository) 是自动负载信息库的英文缩写,AWR报告是Oracle 10g以后版本提供的一种性能收集和分析工具,能提供一个 ...

  5. Oracle批量导出AWR报告

    Oracle批量导出AWR报告 工作需求:项目中需要把生产库中所有的AWR报告dump出来,然后导入到方便测试的数据库中.在测试库中的AWR报告需要根据dbid和实例名逐个导出,如果遇到很多再加上RA ...

  6. SSL/TLS 协议简介与实例分析

    作者:drinkey 以前读RFC时总结的一篇文章,主要介绍了SSL/TLS协议的相关知识,包括协议本身以及简单的密码学概念,以及用实例解析了HTTP over SSL的协商过程,在最后简要列出了SS ...

  7. ORACLE 执行计划分析

    http://www.cnblogs.com/rootq/archive/2008/09/06/1285779.html ORACLE 执行计划分析 一.什么是执行计划 An explain plan ...

  8. php5.4 curl,PHP5.0~5.6 各版本兼容性cURL文件上传功能实例分析

    本文实例分析了PHP5.0~5.6 各版本兼容性cURL文件上传功能.分享给大家供大家参考,具体如下: 最近做的一个需求,要通过PHP调用cURL,以multipart/form-data格式上传文件 ...

  9. php中file对象实例,AJAX_File, FileReader 和 Ajax 文件上传实例分析(php),File FileReader 可以干什么? Ajax - phpStudy...

    File, FileReader 和 Ajax 文件上传实例分析(php) File FileReader 可以干什么?Ajax文件上传例子 FileReader 对象可以读取文件的 Base64编码 ...

最新文章

  1. Linux shell 操作命令 mkdir
  2. jstl与EL表达式处理字符串
  3. 谷歌浏览器怎么设置点击书签 谷歌浏览器如何设置点击书签
  4. Kubernetes 小白学习笔记(31)--kubernetes云原生应用开发-istio架构和安装
  5. 永磁同步电机矢量控制(二)——控制原理与坐标变换推导
  6. 校园网组网方案的设计
  7. MySQL数据恢复--binlog
  8. 目前三大前端主流框架
  9. 3D~RPG游戏的制作
  10. 【NOIP2010普及组】三国游戏题解
  11. 2020年项目经验分享:20厘米厚的无人机激光雷达点云,能否做大比例尺的河道数字高程模型?
  12. codeforces 332b Maximum Absurdity dp
  13. android sqlite 存储对象,SQLite存储对象
  14. 保研之旅7:成电“信息与通信工程学科”夏令营
  15. leetcode 剑指 Offer 03. 数组中重复的数字 抽屉原理 一个萝卜一个坑
  16. 绍中考能不能用计算机了,广州今年中考六科试卷采用计算机辅助评卷
  17. STM32F0系列串口DMA收发数据
  18. [手机APP合集]全是干货!你想要的玩机技巧全在这里了,快来领取!
  19. proxy代理设置总结
  20. 破解版matlab安装Higher Order Spectral Analysis Toolbox-亲测成功

热门文章

  1. Mysql学习总结(65)——项目实战中常用SQL实践总结
  2. Mysql学习总结(62)——MySQL连接com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link问题
  3. linux系统MVS安装,Ubuntu 环境 openMVG+openMVS 配置
  4. php mysql自动反转义_ThinkPHP入库出现两次反斜线转义及数据库类转义的解决方法...
  5. springboot读取src下文件_springboot获取src/main/resource下的文件
  6. js进阶 11-15 jquery过滤方法有哪些
  7. java的多线程机制(文字描述区别)
  8. keepalived vrrp script|interface weight when positive,nagtive,zero vrrp's status transition
  9. 【转】75个最佳Web设计资源
  10. Ubuntu 9.04 死机处理(Linux死机处理)