日期:2014-05-16  浏览次数:20522 次

BULK COLLECT,FORALL,fetch ....limit

BULK COLLECT支持EMPLOYEES%rowtype形式

FORALL插入时不支持EMPLOYEES%rowtype形式,如果有多个字段,要定义多个数组来存放.

    如果插入前有条件判断,可以用VALUES OF

?

?

用fetch .... limit??系统会根据limit的行数向源库逐批获取数据

关于 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 部分可写成:

declare


  type RecTyp is RECORD(


    t dbms_sql.varchar2_table/*bill.hxz1.t%type*/,


    b dbms_sql.varchar2_table/*bill.hxz1.b%type*/);


  l_rec RecTyp;


  cursor c is


    select * from bill.hxz1;


BEGIN


  open c;


  loop


    fetch c bulk collect into l_rec.t,l_rec.b limit 100;


    forall i in 1..l_rec.t.count


      insert into hxz2(t,b) values(l_rec.t(i),l_rec.b(i));


    exit when c%notfound;


  end loop;


  commit;


  close c;


end;

?

?

?

现在你的测试中出现新的错误ORA-06502: ? PL/SQL: ? 数字或值错误,这个问题出现最可能的原因是当最后一次fetch ? cur ? bulk ? collect ? into ? n ? limit ? 10000;的时候,找不到任何记录,所以n.first和n.last是空的,加一句控制就可以。 ?

我之前是把exit ? when ? cur%notfound;放在for循环之前,但是后来发现问题,如果纪录总数不能整除limit参数,那么最后一部份纪录将不会被游标扫描到.
? ?
? declare ?
? ? ? type ? curtype ? is ? ref ? cursor; ?
? ? ? cur ? curtype; ?
? ? ? type ? ntype ? is ? table ? of ? test.col1%type; ?
? ? ? n ? ntype; ?
? ? ? i ? number; ?
? begin ?
? ? ? dbms_output.disable; ?
? ? ? dbms_output.enable(1000000); ?
? ? ? open ? cur ? for ? select ? col1 ? from ? test; ?
? ? ? dbms_output.put_line('第1条记录插入开始:'||to_char(sysdate,'hh24:mi:ss')); ?
? ? ? loop ?
? ? ? ? ? fetch ? cur ? bulk ? collect ? into ? n ? limit ? 10000; ?
? ? ? ? ? if ? n.count ? > ? 0 ? then ? ? -- ? 检查n中的纪录数 ?
? ? ? ? ? ? ? ? ? for ? i ? in ? n.first ? .. ? n.last ? loop ?
? ? ? ? ? ? ? ? ? ? ? insert ? into ? test2 ? (col1,col2) ? values ? (n(i),n(i)*n(i)); ?
? ? ? ? ? ? ? ? ? end ? loop; ?
? ? ? ? ? end ? if; ?
? ? ? ? ? commit; ?
? ? ? ? ? exit ? when ? cur%notfound; ?
? ? ? end ? loop; ?
? ? ? dbms_output.put_line('第'||cur%rowcount||'条记录插入结 束:'||to_char(sysdate,'hh24:mi:ss')); ?
? ? ? close ? cur; ?
? end; ?
? / ?
? ?
? 你成功执行的那段代码中exit ? when放在 ? for ? i ? in ? ...之前,和我加控制的效果是一样的,所以不出错。

?

?

?

?

常在SQL语句中给PL/SQL变量赋值叫做绑定(Binding),一次绑定一个完整的集合称为批量绑定(Bulk ? Binding)。 ?
? ?
? 批量绑定(Bulk ? binds)可以通过减少在PL/SQL和SQL引擎之间的上下文切换(context ? switches ? )提高了性能. ?
? ?
? 批量绑定(Bulk ? binds)包括: ?
? (i) ? Input ? collections, ? use ? the ? FORALL ? statement,一般用来改善DML(INSERT、UPDATE和DELETE) ? 操作的性能 ?
? (ii) ? Output ? collections, ? use ? BULK ? COLLECT ? clause,一般用来提高查询(SELECT)的性能 ?
? ?
? FORALL的语法如下: ?
? ?
? ?
? FORALL ? index ? IN ? lower_bound..upper_bound ? sql_statement; ?

create or replace procedure cp_data2 as
type TYPE_EMPLOYEES is table of EMPLOYEES%rowtype;
  V_EMPLOYEES TYPE_EMPLOYEES;
begin
  select * bulk collect into V_EMPLOYEES from employees @DBLINK1 ;
   for i in 1 .. V_EMPLOYEES.count loop
    insert /*+ APPEND*/ into employee_cp
    (EMPLOYEE_ID,   
FIRST_NAME,   
LAST_NAME,     
EMAIL,         
PHONE_NUMBER,  
HIRE_DATE,     
JOB_ID,        
SALARY,        
COMMISSION_PCT,
MANAGER_ID,   
DEPARTMENT_ID,
BIRTHDAY)
    values
      (V_EMPLOYEES(i).EMPLOYEE_ID,
       V_EMPLOYEES(i).FIRST_NAME,
       V_EMPLOYEES(i).LAST_NAME,
       V_EMPLOYEES(i).EMAIL,
       V_EMPLOYEES(i).PHONE_NUMBER,
       V_