Oracle 中使用 fetch bulk collect into 批量效率的读取游标数据

通常我们获取游标数据是用 fetch some_cursor into var1, var2 的形式,当游标中的记录数不多时不打紧。然而自 Oracle 8i 起,Oracle 为我们提供了 fetch bulk collect 来批量取游标中的数据。它能在读取游标中大量数据的时候提高效率,就像 SNMP 协议中,V2 版比 V1 版新加了 GET-BULK PDU 一样,也是用来更高效的批量取设备上的节点值。

  fetch bulk collect into 的使用格式是:fetch some_cursor collect into col1, col2 limit xxx。col1、col2 是声明的集合类型变量,xxx 为每次取数据块的大小(记录数),相当于缓冲区的大小,可以不指定 limit xxx 大小。下面以实际的例子来说明它的使用,并与逐条取记录的 fetch into 执行效率上进行比较。测试环境是 Oracle 10g  10.2.1.0,查询的联系人表 sr_contacts 中有记录数 1802983 条,游标中以 rownum 限定返回的记录数。

  使用 fetch bulk collect into 获取游标数据

  declare    

   --声明需要集合类型及变量,参照字段的 type 来声明类型      

  type id_type is table of sr_contacts.sr_contact_id%type;     
  v_id id_type;     
       
  type phone_type is table of sr_contacts.contact_phone%type;     
  v_phone phone_type;     
       
  type remark_type is table of sr_contacts.remark%type;     
  v_remark remark_type;   

 

 

   cursor all_contacts_cur is --用 rownum 来限定取出的记录数来测试

 select sr_contact_id,contact_phone,remark from sr_contacts where rownum <= 100000;      

begin    
         
    open all_contacts_cur;     
    loop     
        fetch all_contacts_cur bulk collect into v_id,v_phone,v_remark limit 256;     
        for i in 1..v_id.count loop --遍历集合     
            --用 v_id(i)/v_phone(i)/v_remark(i) 取出字段值来执行你的业务逻辑        
        end loop;     
        exit when all_contacts_cur%notfound; --exit 不能紧接 fetch 了,不然会漏记录     
    end loop;     
    close all_contacts_cur;     
end;   
declare  

 

   --声明需要集合类型及变量,参照字段的 type 来声明类型   

  type id_type is table of sr_contacts.sr_contact_id%type;  
  v_id id_type;  
    
  type phone_type is table of sr_contacts.contact_phone%type;  
  v_phone phone_type;  
    
  type remark_type is table of sr_contacts.remark%type;  
  v_remark remark_type; 

 

 

   cursor all_contacts_cur is --用 rownum 来限定取出的记录数来测试

 select sr_contact_id,contact_phone,remark from sr_contacts where rownum <= 100000;   

begin 
    open all_contacts_cur;  
    loop  
        fetch all_contacts_cur bulk collect into v_id,v_phone,v_remark limit 256;  
        for i in 1..v_id.count loop --遍历集合  
            --用 v_id(i)/v_phone(i)/v_remark(i) 取出字段值来执行你的业务逻辑  
        end loop;  
        exit when all_contacts_cur%notfound; --exit 不能紧接 fetch 了,不然会漏记录  
    end loop;  
    close all_contacts_cur;  
end; 

  使用 fetch into 逐行获取游标数据

  declare 

   --声明变量,参照字段的 type 来声明类型   

  v_id sr_contacts.sr_contact_id%type;  
  v_phone sr_contacts.contact_phone%type;  
  v_remark sr_contacts.remark%type;   

 

   cursor all_contacts_cur is  --用 rownum 来限定取出的记录数来测试   

     select sr_contact_id,contact_phone,remark from sr_contacts where rownum <= 100000;   

begin 
      
    open all_contacts_cur;  
    loop  
        fetch all_contacts_cur into v_id,v_phone,v_remark;  
        exit when all_contacts_cur%notfound;      
        --用 v_id/v_phone/v_remark 取出字段值来执行你的业务逻辑  
        null; --这里只放置一个空操作,只为测试循环取数的效率  
    end loop;  
    close all_contacts_cur;  
end; 
declare

 v_id sr_contacts.sr_contact_id%type;
  v_phone sr_contacts.contact_phone%type;
  v_remark sr_contacts.remark%type;

   cursor all_contacts_cur is  --用 rownum 来限定取出的记录数来测试

     select sr_contact_id,contact_phone,remark from sr_contacts where rownum <= 100000;

begin
   
    open all_contacts_cur;
    loop
        fetch all_contacts_cur into v_id,v_phone,v_remark;
        exit when all_contacts_cur%notfound;   
        --用 v_id/v_phone/v_remark 取出字段值来执行你的业务逻辑
        null; --这里只放置一个空操作,只为测试循环取数的效率
    end loop;
    close all_contacts_cur;
end;

  执行性能比较

  看看测试的结果,分别执行五次所耗费的秒数:

  当 rownum <= 100000 时:

  fetch bulk collect into 耗时:0.125秒, 0.125秒, 0.125秒, 0.125秒, 0.141秒

  fetch into 耗时:      1.266秒, 1.250秒, 1.250秒, 1.250秒, 1.250秒

  当 rownum <= 1000000 时:

  fetch bulk collect into 耗时:1.157秒, 1.157秒, 1.156秒, 1.156秒, 1.171秒

  fetch into 耗时:      12.128秒, 12.125秒, 12.125秒, 12.109秒, 12.141秒

  当 rownum <= 10000 时:

  fetch bulk collect into 耗时:0.031秒, 0.031秒, 0.016秒, 0.015秒, 0.015秒

fetch into 耗时:                 0.141秒, 0.140秒, 0.125秒, 0.141秒, 0.125秒

  当 rownum <= 1000 时:

  fetch bulk collect into 耗时:0.016秒, 0.015秒, 0.016秒, 0.016秒, 0.015秒

  fetch into 耗时:      0.016秒, 0.031秒, 0.031秒, 0.032秒, 0.015秒

  从测试结果来看游标的记录数越大时,用 fetch bulk collect into 的效率很明显示,趋于很小时就差不多了。

  注意了没有,前面使用 fetch bulk collect into 时前为每一个查询列都定义了一个集合,这样有些繁琐。我们之前也许用过表的 %rowtype 类型,同样的我们也可以定义表的 %rowtype 的集合类型。看下面的例子,同时在这个例子中,我们借助于集合的 first、last 属性来代替使用 count  属性来进行遍历。

  declare 

   --声明需要集合类型及变量,参照字段的 type 来声明类型   

  type contacts_type is table of sr_contacts%rowtype;  
  v_contacts contacts_type;   

 

   cursor all_contacts_cur is --用 rownum 来限定取出的记录数来测试   

     select * from sr_contacts where rownum <= 10000;   

begin 
      
    open all_contacts_cur;  
    loop  
        fetch all_contacts_cur bulk collect into v_contacts limit 256;  
        for i in v_contacts.first .. v_contacts.last loop --遍历集合  
            --用 v_contacts(i).sr_contact_id/v_contacts(i).contact_phone/v_contacts(i).remark  
            --的形式来取出各字段值来执行你的业务逻辑    
        end loop;  
        exit when all_contacts_cur%notfound;  
    end loop;  
    close all_contacts_cur;  
end; 
declare

--声明需要集合类型及变量,参照字段的 type 来声明类型

  type contacts_type is table of sr_contacts%rowtype;
  v_contacts contacts_type;

 

   cursor all_contacts_cur is --用 rownum 来限定取出的记录数来测试

     select * from sr_contacts where rownum <= 10000;

begin
   
    open all_contacts_cur;
    loop
        fetch all_contacts_cur bulk collect into v_contacts limit 256;
        for i in v_contacts.first .. v_contacts.last loop --遍历集合
            --用 v_contacts(i).sr_contact_id/v_contacts(i).contact_phone/v_contacts(i).remark
            --的形式来取出各字段值来执行你的业务逻辑
        end loop;
        exit when all_contacts_cur%notfound;
    end loop;
    close all_contacts_cur;
end;

  关于 limit 参数

  你可以根据你的实际来调整 limit 参数的大小,来达到你最优的性能。limit 参数会影响到 pga 的使用率。而且也可以在 fetch bulk 中省略 limit 参数,写成

fetch all_contacts_cur bulk collect into v_contacts;

  有些资料中是说,如果不写 limit 参数,将会以数据库的 arraysize  参数值作为默认值。在 sqlplus 中用 show arraysize  可以看到该值默认为 15,set arraysize 256 可以更改该值。而实际上我测试不带 limit 参数时,外层循环只执行了一轮,好像不是 limit 15,所以不写 limit 参数时,可以去除外层循环,begin-end 部分可写成:

 

begin 
    open all_contacts_cur;  
    fetch all_contacts_cur bulk collect into v_contacts;  
    for i in v_contacts.first .. v_contacts.last loop --遍历集合  
        --用 v_contacts(i).sr_contact_id/v_contacts(i).contact_phone/v_contacts(i).remark  
        --的形式来取出各字段值来执行你的业务逻辑  
        null; --这里只放置一个空操作,只为测试循环取数的效率  
        dbms_output.put_line(2000);  
    end loop;  
    close all_contacts_cur;  
end; 
begin
    open all_contacts_cur;
    fetch all_contacts_cur bulk collect into v_contacts;
    for i in v_contacts.first .. v_contacts.last loop --遍历集合
        --用 v_contacts(i).sr_contact_id/v_contacts(i).contact_phone/v_contacts(i).remark
        --的形式来取出各字段值来执行你的业务逻辑
        null; --这里只放置一个空操作,只为测试循环取数的效率
        dbms_output.put_line(2000);
    end loop;
    close all_contacts_cur;
end;

  bulk collect 的其他用法(总是针对集合)

  select into 语句中,如:

SELECT sr_contact_id,contact_phone BULK COLLECT INTO v_id,v_phone
     FROM sr_contacts WHERE ROWNUM <= 100;
dbms_output.put_line('Count:'||v_id.count||', First:'||v_id(1)||'|'||v_phone(1));

 

  returning into 语句中,如:

DELETE FROM sr_contacts WHERE sr_contact_id < 30
    RETURNING sr_contact_id, contact_phone BULK COLLECT INTO v_id, v_phone;
dbms_output.put_line('Count:'||v_id.count||', First:'||v_id(1)||'|'||v_phone(1));

  forall 的 bulk dml 操作,它大大优于 for 集合后的操作

fetch all_contacts_cur bulk collect into v_contacts;
forall i in 1 .. v_contacts.count
--forall i in v_contacts.first .. v_contacts.last  
--forall i in indices of v_contacts --10g以上,可以是非连续的集合  
insert into sr_contacts(sr_contact_id,contact_phone,remark)
    values(v_contacts(i).sr_contact_id,v_contacts(i).contact_phone,v_contacts(i).remark); 

   --或者是单条的 delete/update 操作

 

 

 

 

转载于:https://www.cnblogs.com/zndavid/archive/2009/06/10/1500323.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262471.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ai钢笔工具怎么描线_骨灰级的AI钢笔工具运用技巧

明白了方向线的方向对曲线形态的影响后&#xff0c;我们来看一下方向线长短造成的影响如下图般&#xff0c;在同一方向上拖拉方向线&#xff1a;(可使用"直接选择工具")对于一个锚点而言&#xff0c;如果方向线越长&#xff0c;那么曲线在这个方向上走的路程就越长&a…

基于注解的事务管理

一、Transactional 注解的源码&#xff0c;定义属性时给默认值 二、基于注解的事务管理代码实现 1、bean.xml中配置 2、业务实施层的代码注解配置&#xff1a; 其中&#xff0c;配在类上则所有方法都被事务管理&#xff0c;也可配置在单独方法上&#xff1b; 转载于:https://ww…

typedef 深入剖析

typedef是一个我们常常会用到的关键字&#xff0c;而这个关键字有许多陷阱或者说许多不为我们深入理解的地方。很多书上都是很简单地一笔代过&#xff0c;并没有真正地让我们理解这个关键字。本文对其进行详细地说明。综合网络上找到的资料对其进行分析&#xff0c;这其中会涉及…

jquery数组(操作数组元素)

HTML&#xff1a; <h3>数组map方法</h3> <div id"show4"></div> jquery&#xff1a; $(document).ready(function(){var animals [dog,cat,tiger,pig,bird]; animals $.map(animals, function(n,i){return i.This is n;});$(#show4).h…

系统分析师考试大纲

一、考试说明 1.考试要求&#xff1a;  &#xff08;1&#xff09;具有系统工程的基础知识&#xff1b;  &#xff08;2&#xff09;掌握开发信息系统的综合技术知识&#xff08;硬件、软件、网络、数据库&#xff09;&#xff1b;  &#xff08;3&#xff09;熟悉企业和…

configure project qt,如何为Qt Framework配置CLion IDE?

How to configure CLion IDE for Qt Framework?Is this IDE compatible with Qt, or are there other IDEs compatible with Qt?I just want to try to use something else than Qt Creator.解决方案I was as desperate as you, until I read this Quora discussion.It worke…

PostgreSQL入门篇学习笔记(七)

2019独角兽企业重金招聘Python工程师标准>>> pg数据库&#xff1a;能提供读写全功能的服务器称为Primary database或者master database。若备份服务器在接受主数据库同步数据和应用同步数据库时&#xff0c;不能提供只读的服务&#xff0c;则该备份数据库称之为warm…

Qt的元对象(Meta-Object)系统简介(转)

Qt的元对象系统基于如下三件事情&#xff1a; 1.类&#xff1a;QObject&#xff0c;为所有需要利用原对象系统的对象提供了一个基类。 2.宏&#xff1a;Q_OBJECT&#xff0c;通常可以声明在类的私有段中&#xff0c;让该类可以使用元对象的特性&#xff0c;比如动态属性&#x…

回归测试的策略

回归测试是贯穿在整个测试的各个阶段的一个测试活动。它的目的是检验已经被发现的缺陷有没有被正确的修改和修改过程中有没有引发新的缺陷。软件在测试或者其他活动中发现的缺陷经过修改后&#xff0c;都要进行回归测试的验证。在做回归测试的时候可以采用不同的策略。 策 略&a…

Meteor创建示例项目 Simple-todos

2019独角兽企业重金招聘Python工程师标准>>> 本笔记&#xff0c;基于Windows环境。 1、Meteor提供了一些示例项目供开发者参考&#xff0c;打开命令行&#xff0c;输入meteor create --list 可以查看提供了哪些示例项目 2、通过meteor create --example <project…

RHEL6下squid代理之正向代理

Squid cache&#xff08;简称为Squid&#xff09;是一个流行的自由软件&#xff08;GNU通用公共许可证&#xff09;的代理服务器和Web缓存服务器。Squid有广泛的用途&#xff0c;从作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度&#xff0c;到为一组人共享…

ASP.NET 使用 X509Certificate2 系统找不到指定的文件

经过虚拟机里面每个用户权限的剥离和对比&#xff0c;最后发现必须要USER的读取权限才能访问证书&#xff01;转载于:https://www.cnblogs.com/zjoch/archive/2009/06/19/1506399.html

跨平台Markdown编辑软件Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

linux精简、备份还原、iso文件、批量安装?

最近小组需要批量自动部署一批机器&#xff0c;把Linux和自己的应用一次批量安装完&#xff0c;每次克隆硬件有点麻烦&#xff0c;因此查了一下相关的资料&#xff0c;看那种方案最好&#xff0c;整理如下。不过没有找到类似windows那样的ghost盘安装的形式&#xff0c;不知网友…

内存总结

(1)lru_file_repage: 当 lru_file_repage 可调参数设置为 1 时&#xff0c;AIX 内核使用这个重新分页信息来确定是否仅选择非计算性的分页进行操作、或者选择计算性的和非计算性的分页进行操作。如果计算性分页的重新分页速度比非计算性分页的重新分页速度高&#xff0c;那么…

如何解决 SQL Server 安装程序中的 COM+ 系统配置检查失败问题

转载自&#xff1a;http://technet.microsoft.com/zh-cn/library/ms143690(SQL.90).aspxSQL Server 2005 联机丛书&#xff08;2008 年 11 月&#xff09;如何解决 SQL Server 安装程序中的 COM 系统配置检查失败问题Microsoft SQL Server 2005 安装程序检查 COM 是否已正确配置…

mysql decimal(6_MySQL(六) decimal数据默认处理

create table decimal_test(id int auto_increment PRIMARY key,score decimal(5,2) -- 取值范围是 -999.99 到 999.99);decimal(M,D)M整数位小数位-- 整数的位数必须小于等于m-d&#xff0c;不然报错。小数的位数可以大于d位。多出d位时会做四舍五入&#xff0c;截取到d位。--…

读取记事本内容,自动发布到新浪微博

想把自己博客上的内容同步到新浪微博上&#xff0c;虽然新浪微博已经提供了关联博客的功能&#xff0c;但那仅限于新发布的微博内容。 手工一条条发布呢&#xff0c;实在枯燥&#xff0c;就想到新浪微博的api接口&#xff0c;结果第一个版本现在已经停止申请了&#xff0c;第二…

Objective-C Runtime 运行时之五:协议与分类

Objective-C中的分类允许我们通过给一个类添加方法来扩充它&#xff08;但是通过category不能添加新的实例变量&#xff09;&#xff0c;并且我们不需要访问类中的代码就可以做到。 Objective-C中的协议是普遍存在的接口定义方式&#xff0c;即在一个类中通过protocol定义接口&…

sqlserver中在建立与服务器的连接时出错

解决&#xff1a;步骤1&#xff1a;在SQLServer 实例上启用远程连接1.指向“开始->程序->Microsoft SQL Server 2005->配置工具->SQL Server 外围应用配置器”2.在“SQL Server 2005 外围应用配置器”页, 单击“服务和连接的外围应用配置器”3.然后单击展开“数据库…