PL/SQL引擎会执行过程化语句,但它把SQL语句发送给SQL引擎处理,然后SQL引擎把处理的结果返回给PL/SQL引擎。

pip sqlalchemy 超时 pl/sql for_forall

PL/SQL和SQL引擎间的频繁切换会大大降低效率。典型的情况就是在一个循环中反复执行SQL语句。

例如,下面的DELETE语句就会在FOR循环中被多次发送到SQL引擎中去:

Declare
  Type numlist Is Varray(20) Of Number;
  depts numlist := numlist(10,30,70);
--department numbers
Begin
  For i In depts.First .. depts.Last Loop
   Delete From emp Where deptno = depts(i);
  End Loop;
End;


这种情况下,如果SQL语句影响了四行或更多行时,使用批量绑定就会显著地提高性能。


用SQL语句中为PL/SQL变量赋值称为绑定,PL/SQL绑定操作可以分为三种:

1.   内绑定(in-bind):用INSERT或UPDATE语句将PL/SQL变量或主变量保存到数据库。 

2.   外绑定(out-bind):通过INSERT、UPDATE或DELETE语句的RETURNING子句的返回值为PL/SQL变量或主变量赋值。 

3.   定义(define):使用SELECT或FETCH语句为PL/SQL变量或主变量赋值。 

DML语句可以一次性传递集合中所有的元素,这个过程就是批量绑定。如果集合有20个元素,批量绑定的一次操作就相当于行20次SELECT、INSERT、UPDATE或DELETE语句。

这项技术是靠减少PL/SQL和SQL引擎间的切换次数来提高性能的。

要对INSERT、UPDATE和DELETE语句使用批量绑定,就要用PL/SQL的FORALL语句。


如果要在SELECT语句中使用批量绑定,我们就要在SELECT语句后面加上一个BULK COLLECT子句来代替INTO子句。



例一:对DELETE语句应用批量绑定 

下面的DELETE语句只往SQL引擎中发送一次,即使是执行了三次DELETE操作:


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 emp Where deptno = depts(i);
End;



这种情况下,如果SQL语句影响了四行或更多行时,使用批量绑定就会显著地提高性能。

1、批量绑定如何提高性能

用SQL语句中为PL/SQL变量赋值称为绑定,PL/SQL绑定操作可以分为三种:

1.   内绑定(in-bind):用INSERT或UPDATE语句将PL/SQL变量或主变量保存到数据库。 

2.   外绑定(out-bind):通过INSERT、UPDATE或DELETE语句的RETURNING子句的返回值为PL/SQL变量或主变量赋值。 

3.   定义(define):使用SELECT或FETCH语句为PL/SQL变量或主变量赋值。 

DML语句可以一次性传递集合中所有的元素,这个过程就是批量绑定。如果集合有20个元素,批量绑定的一次操作就相当于执行20次SELECT、INSERT、UPDATE或DELETE语句。这项技术是靠减少PL/SQL和SQL引擎间的切换次数来提高性能的。要对INSERT、UPDATE和DELETE语句使用批量绑定,就要用PL/SQL的FORALL语句。

如果要在SELECT语句中使用批量绑定,我们就要在SELECT语句后面加上一个BULK COLLECT子句来代替INTO子句。

·        例一:对DELETE语句应用批量绑定 

下面的DELETE语句只往SQL引擎中发送一次,即使是执行了三次DELETE操作:



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 emp Where deptno = depts(i);
End;




·        例二:对INSERT语句应用批量绑定 

下例中,我们把5000个零件编号和名称放到索引表中。所有的表元素都向数据库插入两次:第一次使用FOR循环,然后使用FORALL语句。实际上,FORALL版本的代码执行速度要比FOR语句版本的快得多。


Set serveroutput On;
Create table parts(pnum Number(4), pname Char(15));

Declare
  Type numtab Is Table Of Number(4) Index By Binary_Integer;
  Type nametab Is Table Of Char(15) Index By Binary_Integer;
  pnums  numtab;
  pnames nametab;
  t1     Number;
  t2     Number;
  t3     Number;

Begin
  For j In 1 .. 5000 Loop
    -- load index-by tables
    pnums(j) := j;
    pnames(j) := 'Part No. ' || to_char(j);
  End Loop;
  t1 := dbms_utility.get_time;
  For i In 1 .. 5000 Loop
    -- use FOR loop
    Insert Into parts Values (pnums(i), pnames(i));
  End Loop;
  t2 := dbms_utility.get_time;
  Forall i In 1 .. 5000 -- use FORALL statement
    Insert Into parts Values (pnums(i), pnames(i));
  t3 := dbms_utility.get_time;
  dbms_output.put_line('Execution Time (secs)');
  dbms_output.put_line('---------------------');
  dbms_output.put_line('FOR loop: ' || to_char(t2 - t1));
  dbms_output.put_line('FORALL: ' || to_char(t3 - t2));
End;