Oracle高级PL/SQL
数据的批量处理
游标在处理大批量数据的时候,仅仅启用单核心,会带来性能下降。
通过增强循环语句FORALL和批量绑定语句BULK能够大幅提升性能。
批量绑定
ORACLE的官方文档释意
Oracle Database uses two engines to run PL/SQL units. The PL/SQL engine runs the procedural statements and the SQL engine runs the SQL statements. Every SQL statement causes a context switch between the two engines. You can greatly improve the performance of your database application by minimizing the number of context switches for each PL/SQL unit.
Oracle数据库使用PL/SQL引擎解析过程和函数,使用SQL引擎解析SQL语句,两个引擎相互配合。每个SQL语句都会引起两个引擎之间的上下文切换。如果能够降低两个引擎之间的频繁切换,那么就能最大限度地提升性能,而使用批量绑定语法BULK是能实现。
好处:
BULK 是一次绑定整个集合,通过一次性发送SQL语句供SQL引擎解析的语句。受 SQL 语句影响的行越多,大容量绑定带来的性能提升就越大。考虑使用批量绑定来提高 DML 和 SELECT INTO 引用集合的语句以及 FOR 引用集合并返回 DML 的循环的性能。
实例1:通过bulk批量更新
1 | DECLARE |
实例2:配合Returning和FORALL语句实现批量更新
需要返回值的情况下,使用 Returning 指定
1 | DECLARE |
数据批量更新
实例
1 | OPEN cur_ap_data; |
【注意】对于头行关联的两张表的数据同步,依然要使用游标进行处理
此外,BULK INTO还能用于DML语句
1 | DECLARE |
数据批量删除
通过forall增强循环删除本地大量的数据
实例:根据id来删除
1 | DECLARE |
数据批量插入
性能比较
实验1:大批量复杂查询
以oracle ebs环境为例,同步应付会计分录,数据集为33万+,获取数据集9秒/100条
循环table类型
使用bulk抓取数据到table类型中,然后循环table,每2000条数据提交一次
1.定义table类型
1 | TYPE l_rec_line IS TABLE OF INF_GL_VOUCHERITEMASS%ROWTYPE; |
2.执行阶段
1 | OPEN cur_voucher_lines; |
3.实验结果
耗时1.5小时,共同步48000条数据,平均每分钟533条数据。
【注意】这里都是按整数批量插入,可能会存在抓取数据集的时候停止同步的过程。
游标单行循环
经典游标单循环
1.实现
1 | FOR rec_line IN cur_voucher_lines LOOP |
2.实验结果
耗时1.5小时,共同步49144条数据,平均每分钟546条数据。
实验2:化解复杂查询
以oracle ebs环境为例,头和行的全部会计分类同步。
对于行上要获取头上的数据时,除了使用游标进行双重循环来保证行上能获得头上的数据以外,
还可以通过 先同步行,然后同步头,最后头和行关联,批量update的方式达到数据的最终一致性。
游标双重循环
同步应收发票、应收收款、应付发票、应付付款
1 | for rec_header in cur_header loop |
结果:

批量插入与更新
包定义
1 | CREATE OR REPLACE PACKAGE gj_congl_voucher_sync_v2 IS |
包内容:
1 | CREATE OR REPLACE PACKAGE BODY gj_congl_voucher_sync_v2 IS |
异常处理
查看异常
1.查询表
SELECT * FROM user_errors;

2.SQL * Plus 环境中
show errors;
查看警告信息
PL / SQL 警告的消息代码的格式为 PLW- nnnnn
警告信息等级

查询警告信息等级

可以通过 alter system 修改服务器参数文件

可以通过 alter session 修改当前会话

修改异常信息
启用部分
Alter session set plsql_warnings=’enable:performance’, ‘enable:severe’;

启用全部
Alter session set plsql_warnings=’enable:all’;
针对过程/函数启用编译警告
alter package gj_bc_vld_data_utl compile plsql_warnings = ‘enable:all’;

编辑警告

异常处理准则
- 尽可能编写命名异常的异常处理程序,而不要使用
OTHERS异常处理程序。 - 对于每个异常处理程序,请仔细决定是让它提交事务,回滚它还是让它继续。
- 每个 PL / SQL 程序的顶层都包含一个异常处理程序,避免未处理的异常。并且在子程序中显示抛出异常
RAISE或在RAISE_APPLICATION_ERROR。
异常实例
1.自定义异常实例
1 | CREATE PROCEDURE account_status ( |
2.使用RAISE_APPLICATION_ERROR自定义异常实例
1 | CREATE PROCEDURE account_status ( |
实验:数据同步接口为例
package定义
1 | CREATE OR REPLACE PACKAGE gj_inter_company_sync IS |
package内容
1 | CREATE OR REPLACE PACKAGE BODY gj_inter_company_sync IS |
4.异常事务处理
使用 SAVEPOINT start_transaction; 记录保存点
使用 rollback to [savepoint_name] 回滚保存点
【注意】在使用savepoint期间不能主动 commit ,否则保存点会消失
条件编译
可以根据不同的判断条件,编译/执行不同的程序
语法 $plsql标识符。注意$和标识符之间不能有空格
实例:输出plsql环境参数
1 | BEGIN |
实例2:根据数据库版本执行不同的指令
1 | BEGIN |
其他的环境变量
可以通过 $$[参数名称] 代替在sql命令窗口中的 show parameter [参数名称],以达到在plsql开发工具中查看服务器参数的效果
$$PLSQL_LINE:获取当前package/function的行号$$PLSQL_UNIT:获取当前程序名称$$PLSQL_UNIT_OWNER:获取当前程序owner$$PLSQL_UNIT_TYPE:获取当前程序类型
正则表达式
用到的时候再来总结
数据库锁
同上
闪回技术
Oracle Flashback
实例
查询实例:
1 | SELECT * FROM employees |
数据恢复实例
1 | INSERT INTO employees ( |
闪回事务
消息队列
Oracle AQ
附录
用于管理PLSQL的表

编程规范
正确地使用数据类型
尽可能精确地指定数据类型
- 整数时指定NUMBER(n),而不要使用NUMBER。
- VARCHAR2(n)的精度尽可能准确。
官方参考手册
1.SQL语言参考手册,即SQL Language Reference