【问题标题】:Optimizing row by row (cursor) processing in Oracle 11g在 Oracle 11g 中优化逐行(光标)处理
【发布时间】:2012-02-01 15:39:00
【问题描述】:

为了跟踪两个变量,我必须逐行处理一个大表(2.5B 记录)。可以想象,这是相当缓慢的。我正在寻找有关如何调整此过程的想法。谢谢。

declare
    cursor c_data is select /* +index(data data_pk) */ * from data order by data_id;
    r_data c_data%ROWTYPE;
    lst_b_prc number(15,8);
    lst_a_prc number(15,8);
begin
    open c_data;
    loop
        fetch c_data into r_data;
        exit when c_data%NOTFOUND;

        if r_data.BATS = 'B' then
            lst_b_prc := r_data.PRC;
        end if;
        if r_data.BATS = 'A' then
            lst_a_prc := r_data.PRC;
        end if;
        if r_data.BATS = 'T' then

          insert into trans .... lst_a_prc , lst_b_prc      
           end if;
    end loop;
    close c_data;
end;

问题归结为找到有效的 sql 来跟踪每个 BATS='T' 记录的 BATS='A' 和 BATS='B' 时的最新 PRC 值。

【问题讨论】:

    标签: oracle stored-procedures query-optimization oracle11g


    【解决方案1】:

    有多种选择。最重要的是,您可能会为所有插入保留一个巨大的 UNDO/REDO 日志。你可以偶尔提交你的工作,比如每 1000 次插入。

    另一种选择是使用SQL MERGE 语句(或更简单的INSERT .. SELECT .. 语句),这将允许您的Oracle 实例对集合而不是单个记录进行操作。您选择的执行计划可能会针对INSERT 的最佳性能进行优化。

    【讨论】:

    • 您对巨大的撤消表空间是正确的。我创建了一个近 300GB 的大文件表空间来容纳这个过程。 SQL MERGE 似乎很有趣。我不确定如何准确地应用它。再想一想,问题真的归结为找到有效的 sql 来跟踪每个 BATS='T' 记录的 BATS='A' 和 BATS='B' 时的最新 PRC 值。
    【解决方案2】:

    如果我正确理解您的问题,请使用如下数据表:

    create table data as
    select 1 data_id, 'T' bats, 1 prc from dual union all
    select 2 data_id, 'A' bats, 2 prc from dual union all
    select 3 data_id, 'B' bats, 3 prc from dual union all
    select 4 data_id, 'T' bats, 4 prc from dual union all
    select 5 data_id, 'A' bats, 5 prc from dual union all
    select 6 data_id, 'T' bats, 6 prc from dual union all
    select 7 data_id, 'B' bats, 7 prc from dual union all
    select 8 data_id, 'T' bats, 8 prc from dual union all
    select 9 data_id, 'T' bats, 9 prc from dual;
    

    您想为每个 T 插入一行,使用 A 和 B 的最后一个 PRC 值。看起来像这样:

    T data_id   Last A   Last B
    ---------   ------   ------
    1           null     null
    4           2        3
    6           5        3
    8           5        7
    9           5        7
    

    这个查询应该可以工作:

    select data_id, last_A, last_B
    from
    (
        select data_id, bats, prc
            ,max(case when bats = 'A' then prc else null end) over
                (order by data_id
                 rows between unbounded preceding and current row) last_A
            ,max(case when bats = 'B' then prc else null end) over
                (order by data_id
                 rows between unbounded preceding and current row) last_B
        from data
    )
    where bats = 'T';
    

    有了这么多数据,您可能希望使用直接路径写入和并行性。 性能在很大程度上取决于分析函数的排序是否可以在内存或磁盘中完成。优化内存可能非常困难,您可能需要与 DBA 合作,以允许您的进程使用尽可能多的内存,而不会给其他进程造成问题。

    【讨论】:

    • 谢谢。这看起来正是我需要的。我将在开发服务器上对其进行测试并报告性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    相关资源
    最近更新 更多