暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Scheduling

2011-01-01
365

JL Computer Consultancy

A demonstration of controlling concurrent processing.

June  1999


In previous articles I demonstrated how to generate a covering set of rowid ranges for a table, and a package for allocating tasks from a list to multiple concurrent processes with minimal contention. In this article I put the two packages together to show how you can update a very large table in discrete sections to get the maximum possible performance from your system.

There are 4 sections to the page.

Section 1

Building a sample data set, get the rowid ranges, populate the control table for the parallel process

Section 2

A procedure to acquire and lock a rowid range, then update that range's set of data

Section 3

A simple shell script that can be executed multiple times to select the parallelism

Section 4

A simple SQL script to reset the flags on the control table to repeat the experiment

Before you can run this demonstration, you will need to create a suitably privileged account, and the three packages that allow it to work - jpl_utils (to convert decimal to hex), y2k_tools to generate the rowid ranges, and parallel_allocation to control the concurrent processes.

The account you use will have to have the privilege to select from dba_extents, and to execute pacakge dbms_lock granted directly to it, as these objects are used in the support packages.


Preparing the demonstration

rem
复制
rem     Script:        cc_make.sql
复制
rem     Author:        Jonathan Lewis
复制
rem     Dated:         1-June-1999
复制
rem     Purpose:       Prepare demo data for concurrent processing
复制
rem
复制
rem
复制
rem     Create a sample table
复制
rem
复制
create table upd_demo
复制
unrecoverable
复制
tablespace tools
复制
storage (initial 480K next 480K)
复制
as
复制
select * from sys.source$
复制
;
复制
rem
复制
rem     Generate the rowid ranges
复制
rem
复制
begin
复制
        y2k_tools.generate_rowid_ranges(
复制
               'JPL','UPD_DEMO',480
复制
        );
复制
end;
复制
/
复制
rem
复制
rem     Copy the rowid ranges into the
复制
rem     generic 'parallel allocation' table
复制
rem
复制
declare
复制
        v_ret_code     number;
复制
        v_err_msg      varchar2(128);
复制
begin
复制
        -- 'Create' the table
复制
        parallel_allocation.create_driver(
复制
               i_driving_task   => 'Update demo',
复制
               io_return_code   => v_ret_code,
复制
               io_error_message => v_err_msg
复制
        );
复制
        if (v_ret_code != parallel_allocation.c_success) then
复制
               dbms_output.put_line('Error: ' || v_ret_code);
复制
               dbms_output.put_line(v_err_msg);
复制
               raise_application_error(-20001, 'Broken');
复制
        end if;
复制
        -- Populate the table
复制
        -- Note that we are selecting from the y2k_tools table, one row at a time
复制
        -- We could build a special version of the parallel_allocation package to 
复制
        -- use the y2k_tools table directly, but one reason for having packages at
复制
        -- all is so that we can re-use generic code.
复制
        for r1 in (select * from rowid_control) loop
复制
               parallel_allocation.populate_driver(
复制
                       i_driving_task          => 'Update demo',
复制
                       i_payload               => r1.rowid_start || '-' || 
复制
                                                 r1.rowid_end,
复制
                       io_return_code          => v_ret_code,
复制
                       io_error_message        => v_err_msg
复制
               );
复制
               if (v_ret_code != parallel_allocation.c_success) then
复制
                       dbms_output.put_line('Error: ' || v_ret_code);
复制
                       dbms_output.put_line(v_err_msg);
复制
                       raise_application_error(-20001, 'Broken');
复制
               end if;
复制
        end loop;
复制
end;
复制
/
复制
commit;
复制

Procedure to get one control row and update the associated data

rem
复制
rem     cc_update.sql
复制
rem
复制
rem     Loop requesting a row from the allocation table
复制
rem     if there are any control rows left
复制
rem            update (and count) the rows in the range
复制
rem            mark the control row as done
复制
rem     else if a problem arises
复制
rem            bomb out
复制
rem     else
复制
rem            end
复制
rem
复制
rem
复制
set serveroutput on size 10000
复制
set timing on
复制
create or replace procedure do_update as
复制
        v_continue     boolean := true;
复制
        v_count        number(8) := 0;
复制
        v_total        number(8) := 0;
复制
        v_ret_code     number(2);
复制
        v_err_msg      varchar2(80);
复制
        v_payload      varchar2(40);
复制
        v_rowid_start  rowid;
复制
        v_rowid_end    rowid;
复制
begin
复制
        while v_continue loop
复制
               parallel_allocation.allocate_target_item(
复制
                       i_driving_task   => 'Update demo',
复制
                       o_payload        => v_payload,
复制
                       io_return_code   => v_ret_code,
复制
                       io_error_message => v_err_msg
复制
               );
复制
               if (v_ret_code = parallel_allocation.c_no_rows_left) then
复制
                       v_continue := false;
复制
               elsif (v_ret_code = parallel_allocation.c_success) then
复制
                       v_rowid_start := chartorowid(substr(v_payload,1,18));
复制
                       v_rowid_end   := chartorowid(substr(v_payload,20));
复制
                       update /*+ rowid(t) */ upd_demo t
复制
                       set line = line + 1
复制
                       where rowid between v_rowid_start 
复制
                       and v_rowid_end;
复制
                       v_count := sql%rowcount;
复制
                       v_total := v_total + v_count;
复制
                       dbms_output.put_line(
复制
                               'Rows: ' || v_count || ' - ' || v_total
复制
                       );
复制
                       parallel_allocation.complete_target_item(
复制
                               i_driving_task   => 'Update demo',
复制
                               i_payload        => v_payload,
复制
                               io_return_code   => v_ret_code,
复制
                               io_error_message => v_err_msg
复制
                       );
复制
                       if (v_ret_code != parallel_allocation.c_success) then
复制
                               dbms_output.put_line('Error: ' || v_ret_code);
复制
                               dbms_output.put_line(v_err_msg);
复制
                               raise_application_error(-20001, 'Broken');
复制
                       end if;
复制
               else
复制
                       v_continue := false;
复制
                       dbms_output.put_line('Error: ' || v_ret_code);
复制
                       dbms_output.put_line(v_err_msg);
复制
                       raise_application_error(-20001, 'Broken');
复制
               end if;
复制
        end loop;
复制
end;
复制
.
复制
/
复制

A shell script to run one copy of the update

#!/bin/ksh
复制
#
复制
#       cc_demo.ksh
复制
#
复制
sqlplus -s jpl/jpl  <<-!!!
复制
set serveroutput on size 100000
复制
set timing on
复制
execute do_update;
复制
exit
复制
!!!
复制

An SQL script to reset all the control rows

rem
复制
rem     cc_reset.sql
复制
rem     Quick fix to clear all the flags
复制
rem
复制
declare
复制
        v_return_code number(2);
复制
        v_error_message varchar2(80);
复制
begin
复制
parallel_allocation.reset_all_targets(
复制
               i_driving_task         => 'Update demo',
复制
               io_return_code         => v_return_code,
复制
               io_error_message       => v_error_message
复制
);
复制
end;
复制
/
复制


最后修改时间:2020-04-16 14:52:28
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论