9i10g11g编程艺术——过程并行化

你可能经常看到,设计为串行执行的应用(一般是批处理应用)往往类似于以下过程:
create or replace procedure serial
is
begin
    for x in (select object_id id, object_name text from big_table)
    loop
        insert into t2 (id, text) values (x.id, x.text);
    end loop;
end;
/

在这种情况下,oracle的并行查询或PDML没有什么帮组。如果oracle并行的执行简单的select object_id id, object_name text from big_table,可能不会提供任何显著的速度提升。如果oracle在完成复杂的处理之后再并行的执行update或insert,则没有任何好处,毕竟这里只会update/insert一行。
从oracle11g R2开始,有了一种新的方法可以通过dbms_parallel_execute内置包实现并行化。其实原理也比较简 单:首先是把数据分成一个个CHUNK,然后指定并行度来同时执行这些任务。就类似手工的按照主键、ROWID或者数据的日期等等进行并行处理类似。现在修改serial过程,如下所示:
create or replace procedure serial( p_lo_rid in rowid, p_hi_rid in rowid)
is
begin
    for x in (select object_id id, object_name text from big_table  where rowid between p_lo_rid and p_hi_rid)
    loop
        insert into t2 (id, text,   session_id) values (x.id, x.text,   sys_context('userenv', 'sessionid'));
    end loop;
end;
/

使用dbms_parallel_execute一般分为3个步骤:创建一个TASK;然后创建CHUNK把数据进行分批;最后是执行这个TASK。下面来做一个演示,演示更新一个表的过程:
1、首先创建一个TASK
u1@ORCL> exec dbms_parallel_execute.create_task('process big table');
PL/SQL 过程已成功完成。

u1@ORCL> select task_name,chunk_type,status from dba_parallel_execute_tasks;

TASK_NAME            CHUNK_TYPE   STATUS
-------------------- ------------ -------------------
process big table    UNDELARED    CREATED

2、把将要更新的表按照ROWID进行分批,分到各个CHUNK中
u1@ORCL> begin
  2      dbms_parallel_execute.create_chunks_by_rowid
  3      ( task_name   => 'process big table',
  4        table_owner => user,
  5        table_name  => 'BIG_TABLE',
  6        by_row      => false,
  7        chunk_size  => 10000 );
  8  end;
  9  /
PL/SQL 过程已成功完成。

u1@ORCL> select *
  2    from (select chunk_id, task_name, status, start_rowid, end_rowid
  3            from dba_parallel_execute_chunks
  4           where task_name = 'process big table'
  5           order by chunk_id)
  6   where rownum <= 5;

  CHUNK_ID TASK_NAME            STATUS               START_ROWID        END_ROWID
---------- -------------------- -------------------- ------------------ ------------------
         1 process big table    UNASSIGNED           AAAZJSAAEAAAADIAAA AAAZJSAAEAAAADPCcP
         2 process big table    UNASSIGNED           AAAZJSAAEAAAADQAAA AAAZJSAAEAAAADXCcP
         3 process big table    UNASSIGNED           AAAZJSAAEAAAADYAAA AAAZJSAAEAAAADfCcP
         4 process big table    UNASSIGNED           AAAZJSAAEAAAADgAAA AAAZJSAAEAAAADnCcP
         5 process big table    UNASSIGNED           AAAZJSAAEAAAADoAAA AAAZJSAAEAAAADvCcP

BY_ROW:分CHUNK的类型。如果为TRUE,则后面的CHUNK_SIZE表示是行;如果是FALSE,则后面的CHUNK_SIZE表示的是BLOCK。
CHUNK_SIZE:CHUNK大小。如果BY_ROW为TRUE,表示多少行分为一个CHUNK;如果BY_ROW为FALSE,则表示多少块分为一个CHUNK。

3、执行并行任务
u1@ORCL> begin
  2      dbms_parallel_execute.run_task
  3      ( task_name      => 'process big table',
  4        sql_stmt       => 'begin serial( :start_id, :end_id ); end;',
  5        language_flag  => DBMS_SQL.NATIVE,
  6        parallel_level => 4 ); 
  7  end;
  8  /
PL/SQL 过程已成功完成。

在执行过程中可以通过dba_parallel_execute_chunks视图观察执行情况,预估大致完成时间。如果某个chunk失败,可以纠正发生错误的根本原因,其它chunk会继续执行,知道所有chunk都成功完成时,就大功告成了。下面将任务删除:

u1@ORCL> exec dbms_parallel_execute.drop_task('process big table' );
PL/SQL 过程已成功完成。

如果查看我们自己的应用表,可以看到有4个并行作业,其中每个作业处理的行数大致相同:
u1@ORCL> select session_id, count(*)
  2    from t2
  3   group by session_id
  4   order by session_id;

SESSION_ID   COUNT(*)
---------- ----------
    435120    2576610
    435121    2468963
    435122    2250216
    435123    2704211


你可能感兴趣的:(9i10g11g编程艺术——过程并行化)