热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据库技术:浅谈PL/SQL批处理语句:BULKCOLLECT与FORALL对优化做出的贡献

我们知道plsql程序中运行sql语句是存在开销的,因为sql语句是要提交给sql引擎处理这种在plsql引擎和sql引擎之间的控制转移叫做上下文却

我们知道pl/sql程序中运行sql语句是存在开销的,因为sql语句是要提交给sql引擎处理
这种在pl/sql引擎和sql引擎之间的控制转移叫做上下文却换,每次却换时,都有额外的开销

请看下图:

浅谈PL/SQL批处理语句:BULK COLLECT与FORALL对优化做出的贡献

但是,forall和bulk collect可以让pl/sql引擎把多个上下文却换压缩成一个,这使得在pl/sql中的要处理多行记录的sql语句执行的花费时间骤降
请再看下图:

浅谈PL/SQL批处理语句:BULK COLLECT与FORALL对优化做出的贡献

下面详解这爷俩

㈠ 通过bulk collect 加速查询

⑴ bulk collect 的用法

采用bulk collect可以将查询结果一次性地加载到collections中,而不是通过cursor一条一条地处理
可以在select into ,fetch into , returning into语句使用bulk collect
注意在使用bulk collect时,所有的into变量都必须是collections

举几个简单例子:

① 在select into语句中使用bulk collect

代码如下:
declare
type sallist is table of employees.salary%type;
sals sallist;
begin
select salary bulk collect into sals from employees where rownum<=50;
–接下来使用集合中的数据
end;
/

② 在fetch into中使用bulk collect

代码如下:
declare
type deptrectab is table of departments%rowtype;
dept_recs deptrectab;
cursor cur is select department_id,department_name from departments where department_id>10;
begin
open cur;
fetch cur bulk collect into dept_recs;
–接下来使用集合中的数据
end;
/

③ 在returning into中使用bulk collect

代码如下:
create table emp as select * from employees;

declare
type numlist is table of employees.employee_id%type;
enums numlist;
type namelist is table of employees.last_name%type;
names namelist;
begin
delete emp where department_id=30
returning employee_id,last_name bulk collect into enums,names;
dbms_output.put_line(‘deleted’||sql%rowcount||’rows:’);
for i in enums.first .. enums.last
loop
dbms_output.put_line(’employee#’||enums(i)||’:’||names(i));
end loop;
end;
/

deleted6rows:
employee#114:raphaely
employee#115:khoo
employee#116:baida
employee#117:tobias
employee#118:himuro
employee#119:colmenares

eate table emp as select * from employees;declare type numlist is table of employees.employee_id%type; enums numlist; type namelist is table of employees.last_name%type; names namelist;begin delete emp where department_id=30 returning employee_id,last_name bulk collect into enums,names; dbms_output.put_line(‘deleted’||sql%rowcount||’rows:’); for i in enums.first .. enums.last loop dbms_output.put_line(’employee#’||enums(i)||’:’||names(i)); end loop;end;/deleted6rows:employee#114:raphaelyemployee#115:khooemployee#116:baidaemployee#117:tobiasemployee#118:himuroemployee#119:colmenares

⑵ bulk collect 对大数据delete update的优化

这里举delete就可以了,update同理

举个案例:
需要在一个1亿行的大表中,删除1千万行数据
需求是在对数据库其他应用影响最小的情况下,以最快的速度完成

如果业务无法停止的话,可以参考下列思路:
根据rowid分片、再利用rowid排序、批量处理、回表删除
在业务无法停止的时候,选择这种方式,的确是最好的
一般可以控制在每一万行以内提交一次,不会对回滚段造成太大压力
我在做大dml时,通常选择一两千行一提交
选择业务低峰时做,对应用也不至于有太大影响
代码如下:

代码如下:
declare
–按rowid排序的cursor
–删除条件是oo=xx,这个需根据实际情况来定
cursor mycursor is select rowid from t where oo=xx order by rowid;
type rowid_table_type is table of rowid index by pls_integer;
v_rowid rowid_table_type;
begin
open mycursor;
loop
fetch mycursor bulk collect into v_rowid limit 5000;–5000行提交一次
exit when v_rowid.count=0;
forall i in v_rowid.first..v_rowid.last
delete t where rowid=v_rowid(i);
commit;
end loop;
close mycursor;
end;
/

⑶ 限制bulk collect 提取的记录数

语法:
fetch cursor bulk collect into …[limit rows];
其中,rows可以是常量,变量或者求值的结果是整数的表达式

假设你需要查询并处理1w行数据,你可以用bulk collect一次取出所有行,然后填充到一个非常大的集合中
可是,这种方法会消耗该会话的大量pga,app可能会因为pga换页而导致性能下降

这时,limit子句就非常有用,它可以帮助我们控制程序用多大内存来处理数据

例子:

代码如下:
declare
cursor allrows_cur is select * from employees;
type employee_aat is table of allrows_cur%rowtype index by binary_integer;
v_emp employee_aat;
begin
open allrows_cur;
loop
fetch allrows_cur bulk fetch into v_emp limit 100;

/*通过扫描集合对数据进行处理*/
for i in 1 .. v_emp.count
loop
upgrade_employee_status(v_emp(i).employee_id);
end loop;

exit when allrows_cur%notfound;
end loop;

close allrows_cur;
end;
/

⑷ 批量提取多列

需求:
提取transportation表中的油耗小于 20公里/rmb的交通具体的全部信息
代码如下:

代码如下:
declare
–声明集合类型
type vehtab is table of transportation%rowtype;
–初始化一个这个类型的集合
gas_quzzlers vehtab;
begin
select * bulk collect into gas_quzzlers from transportation where mileage <20;

⑸ 对批量操作使用returning子句

有了returning子句后,我们可以轻松地确定刚刚完成的dml操作的结果,无须再做额外的查询工作
例子请见bulk collect 的用法的第三小点

㈡ 通过forall 加速dml

forall告诉pl/sql引擎要先把一个或多个集合的所有成员都绑定到sql语句中,然后再把语句发送给sql引擎

⑴ 语法

未完待续。。。

需要了解更多数据库技术:浅谈PL/SQL批处理语句:BULK COLLECT与FORALL对优化做出的贡献,都可以关注数据库技术分享栏目—编程笔记


推荐阅读
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 基于事件驱动的并发编程及其消息通信机制的同步与异步、阻塞与非阻塞、IO模型的分类
    本文介绍了基于事件驱动的并发编程中的消息通信机制,包括同步和异步的概念及其区别,阻塞和非阻塞的状态,以及IO模型的分类。同步阻塞IO、同步非阻塞IO、异步阻塞IO和异步非阻塞IO等不同的IO模型被详细解释。这些概念和模型对于理解并发编程中的消息通信和IO操作具有重要意义。 ... [详细]
author-avatar
mobiledu2502856653
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有