Oracle APEX - 数据库中过程内部的并行执行

问题描述 投票:0回答:1

我有一个程序需要时间来执行。单击提交按钮后从 Oracle APEX 调用该过程,但 30 分钟后超时。由于用户不想让这个作业在后台运行,我决定看看它的性能是否可以提高。

所以,我想到了并行执行。但是,我收到一条错误消息:ORA-29491:无效表用于分块 ORA-06512:位于“XX_WFM.XXMWC_WFM_FRINGES。staging_fringe_data 是全局临时表。

数据库是Oracle 19c

PROCEDURE recalculate_fringe_spread(
  p_budget_year_id IN xx_wfm_salary_distribution.budget_year_id%TYPE
)
IS
  l_scope      insum_error_log.scope%TYPE := 'RECALCULATE_FRINGE_SPREAD';
  l_parameters insum_debug.tab_param := insum_debug.tab_param();
  l_task_name  CONSTANT VARCHAR2(100) := 'RECALCULATE_FRINGE_SPREAD_TASK';
BEGIN
  insum_debug.append_param(l_parameters, 'P_BUDGET_YEAR_ID', p_budget_year_id);
  insum_debug.log_start(l_scope, NULL, l_parameters);
  -- Check if the staging table exists, create it if not
  -- Populate staging table
  INSERT INTO staging_fringe_data
  SELECT b.rate_type,
         b.fb_account,
         a.alternate_allemployee_rate,
         a.alternate_medicare_rate,
         a.alternate_irs_limit,
         d.id AS chunk_id
    FROM xx_wfm_fringe_benefit a
    JOIN xx_wfm_fringe_benefit_dtl b ON b.fringe_benefit_id = a.id
    JOIN xx_wfm_salary_distribution d ON d.budget_year_id = a.budget_year_id
                                       AND d.natural_account BETWEEN b.from_account AND b.to_account
                                       AND d.fund BETWEEN b.from_fund AND b.to_fund
   WHERE d.budget_year_id = p_budget_year_id;
  COMMIT;
  -- Create task
  DBMS_PARALLEL_EXECUTE.create_task(l_task_name);
  -- Create chunks by COLUMN
  DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_NUMBER_COL(
    task_name     => 'RECALCULATE_FRINGE_SPREAD_TASK',
    table_owner   => 'XX_WFM',
    table_name    => 'STAGING_FRINGE_DATA',
    table_column   => 'CHUNK_ID',
    chunk_size    => 1000
  );
  -- Define SQL statement for parallel execution
  DECLARE
    l_sql_stmt VARCHAR2(4000);
  BEGIN
    l_sql_stmt := 'BEGIN
                     xx_wfm_budget.spread_fringe_benefit(
                       p_salary_distribution_id => :chunk_id,
                       p_fringe_natural_account => :fb_account,
                       p_spread_type           => :rate_type,
                       lv_alternate_allemployee_rate  => :alternate_allemployee_rate
                       lv_alternate_medicare_rate     => :alternate_medicare_rate
                       p_cap_limit             => :alternate_irs_limit
                     );
                   END;';
                   
    -- Run task
    DBMS_PARALLEL_EXECUTE.run_task(
      task_name      => l_task_name,
      sql_stmt       => l_sql_stmt,
      language_flag  => DBMS_SQL.NATIVE,
      parallel_level => 5
    );
  END;
  -- Drop task
  DBMS_PARALLEL_EXECUTE.drop_task(l_task_name);
  -- Cleanup staging table
  EXECUTE IMMEDIATE 'TRUNCATE TABLE staging_fringe_data';
  insum_debug.log_end(l_scope, NULL, l_parameters);
EXCEPTION
  WHEN OTHERS THEN
    insum_debug.log_error(p_text   => SQLERRM,
                          p_scope  => l_scope,
                          p_params => l_parameters,
                          p_app    => COALESCE(v('APP_ID'), NULL));
    DBMS_PARALLEL_EXECUTE.drop_task(l_task_name);
    EXECUTE IMMEDIATE 'TRUNCATE TABLE staging_fringe_data';
    RAISE;
END recalculate_fringe_spread;```
plsql parallel-processing oracle-apex oracle19c
1个回答
0
投票

您说“用户不想将此作业推到后台”。好吧...无论如何你都可以在后台执行作业。在 UI 端创建一个页面,其中包含“动态内容”类型的区域,显示“正在处理...请等待”,每 x 秒刷新一次,直到作业完成。这样它就会作为一项作业在后台运行 - 因此它不会超时,但用户会认为它是动态运行。

© www.soinside.com 2019 - 2024. All rights reserved.