我有一个程序需要时间来执行。单击提交按钮后从 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;```
您说“用户不想将此作业推到后台”。好吧...无论如何你都可以在后台执行作业。在 UI 端创建一个页面,其中包含“动态内容”类型的区域,显示“正在处理...请等待”,每 x 秒刷新一次,直到作业完成。这样它就会作为一项作业在后台运行 - 因此它不会超时,但用户会认为它是动态运行。