优化 PL/SQL 代码 [关闭]
Posted
技术标签:
【中文标题】优化 PL/SQL 代码 [关闭]【英文标题】:Optimize PL/SQL code [closed] 【发布时间】:2014-10-08 09:39:10 【问题描述】:我知道在没有规范的情况下很难对代码进行一些优化,但我也没有规范。任何人都可以在下面的代码中进行一些优化吗?因为这段代码执行超过 6 天,但我们需要在 6 或 8 小时内运行它。有什么建议吗?
PROCEDURE kzt_2_27_p ( p_start_date DATE, p_end_date DATE )
AS
CURSOR cur1
IS
SELECT cal.id,
cal.dt,
cal.id_period,
per.period_name
FROM xxkkbi_dim_calendar cal,
xxkkbi_dim_period per
WHERE
( cal.dt BETWEEN p_start_date AND p_end_date )
AND
per.id = cal.id_period
ORDER BY cal.dt;
row1 cur1%ROWTYPE;
l_year_sum NUMBER;
l_id_specific NUMBER;
l_region VARCHAR2 ( 10 CHAR );
l_period_name VARCHAR2 ( 10 CHAR );
l_id_region NUMBER;
l_id_date NUMBER;
l_id_period NUMBER;
l_segment4 VARCHAR2 ( 30 CHAR );
--------- For Log -------------------------------
l_fct VARCHAR2 ( 20 ) := 'FCT_2_27';
l_date DATE;
l_descr VARCHAR2 ( 2000 CHAR ) := '';
l_err_code VARCHAR2 ( 20 CHAR );
l_err_msg VARCHAR2 ( 2000 CHAR );
--------- End For Log ----------------------------
BEGIN
pkg_fct_log.fct_log_2 ( p_fct_name => l_fct, p_oper_name => 'START PROCEDURE' );
FOR row1 IN cur1
LOOP
l_date := row1.dt;
l_period_name := row1.period_name;
l_id_period := row1.id_period;
l_id_date := row1.id;
DELETE FROM xxkkbi.fct_2_27 WHERE id_date = l_id_date AND id_period = l_id_period;
FOR row2 IN ( SELECT id, code
FROM xxkkbi_dim_region
WHERE code NOT IN ('0000', '0077', '5899', '0098', '0099', 'T', '6300') AND id > -1 )
LOOP
l_region := row2.code;
l_id_region := row2.id;
INSERT INTO temp_2_27
SELECT cc.segment4,
SUM ( DECODE ( cc.segment3, '000000000', NVL ( accounted_cr, 0 ) - NVL ( accounted_dr, 0 ), 0 ) ) sum_in,
SUM ( DECODE ( cc.segment3, '019999999', NVL ( accounted_cr, 0 ) - NVL ( accounted_dr, 0 ), 0 ) ) sum_out,
SUM ( DECODE ( cc.segment3, '000000000', 0, '019999999', 0, NVL ( accounted_cr, 0 ) - NVL ( accounted_dr, 0 ) ) ) sum_zach,
id_specific
FROM gl_gl_je_lines l,
gl_gl_je_headers h,
(SELECT
code_combination_id,
specific.id id_specific,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific
WHERE
chart_of_accounts_id = 50408
AND
template_id IS NULL
AND (
segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND
segment2 LIKE CASE WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND ( segment3 IN ('000000000', '019999999') OR segment3 BETWEEN '021999999' AND '023999999' )
AND segment4 BETWEEN '100000' AND '8ßßßßß'
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific.code
AND specific.date_end >= l_date
) cc
WHERE h.ledger_id = 2021
AND h.actual_flag = 'A'
AND h.currency_code = 'KZT'
AND h.je_header_id = l.je_header_id
AND l.code_combination_id = cc.code_combination_id
AND l.ledger_id = h.ledger_id
AND l.status = 'P'
AND l.period_name = l_period_name
AND l.effective_date = l_date
GROUP BY
cc.segment4,
cc.id_specific;
FOR row3 IN (
SELECT
segment4,
sum_in,
sum_out,
sum_zach,
id_specific
FROM temp_2_27 )
LOOP
l_segment4 := row3.segment4;
l_id_specific := row3.id_specific;
SELECT NVL ( SUM ( sum_spec ), 0 )
INTO l_year_sum
FROM (
SELECT
cc.segment4,
-1 * end_of_date_balance_num sum_spec
FROM apps_gl_daily_balances_v db,
(SELECT
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 IN ('000000000', '019999999')
AND segment4 = l_segment4
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
db.code_combination_id = cc.code_combination_id
AND db.ledger_id = 2021
AND db.actual_flag = 'A'
AND db.currency_type = 'U'
AND db.currency_code = 'KZT'
AND db.period_set_name = 'КЗ Календарь'
AND db.period_name = l_period_name
AND db.accounting_date = l_date
UNION ALL
SELECT
cc.segment4,
NVL ( accounted_cr, 0 ) - NVL ( accounted_dr, 0 ) sum_spec
FROM
gl_gl_je_lines l,
gl_gl_je_headers h,
(SELECT
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND
template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 BETWEEN '021999999' AND '023999999'
AND segment4 = l_segment4
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
h.ledger_id = 2021
AND h.actual_flag = 'A'
AND h.currency_code = 'KZT'
AND h.je_header_id = l.je_header_id
AND l.code_combination_id = cc.code_combination_id
AND l.ledger_id = h.ledger_id
AND l.status = 'P'
AND l.period_name = l_period_name
AND l.effective_date BETWEEN TRUNC ( l_date, 'MM' )
AND l_date
UNION ALL
SELECT
cc.segment4,
NVL ( begin_balance_cr, 0 ) - NVL ( begin_balance_dr, 0 ) sum_spec
FROM
gl_gl_balances db,
(SELECT
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 BETWEEN '021999999' AND '023999999'
AND segment4 = l_segment4
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
db.code_combination_id = cc.code_combination_id
AND db.ledger_id = 2021
AND db.actual_flag = 'A'
AND db.currency_code = 'KZT'
AND db.period_name = l_period_name
);
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'START INSERT',
p_rows_date => l_date,
p_oper_descr => l_descr
|| ' l_id_specific='
|| l_id_specific
|| ' l_year_sum='
|| l_year_sum
);
INSERT INTO
xxkkbi.fct_2_27
SELECT
l_id_date,
l_id_period,
-1,
l_id_specific,
l_id_region,
row3.sum_in,
row3.sum_out,
row3.sum_zach,
l_year_sum
FROM DUAL;
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'END INSERT',
p_rows_count => 1,
p_rows_date => l_date,
p_oper_descr => l_descr
|| ' l_id_specific='
|| l_id_specific
|| ' l_year_sum='
|| l_year_sum
);
END LOOP;
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'START INSERT',
p_rows_date => l_date,
p_oper_descr => l_descr
);
INSERT INTO
xxkkbi.fct_2_27
SELECT
l_id_date AS id_date,
l_id_period,
-1,
id_specific,
l_id_region,
0,
0,
0,
sum_spec
FROM
(
SELECT
t1.id_specific,
NVL ( SUM ( t1.sum_spec ), 0 ) sum_spec
FROM
(SELECT
id_specific,
-1 * end_of_date_balance_num sum_spec
FROM
apps_gl_daily_balances_v db,
(SELECT
specific2.id id_specific,
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 IN ('000000000', '019999999')
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
db.code_combination_id = cc.code_combination_id
AND db.ledger_id = 2021
AND db.actual_flag = 'A'
AND db.currency_type = 'U'
AND db.currency_code = 'KZT'
AND db.period_set_name = 'ÊÇ Êàëåíäàðü'
AND db.period_name = l_period_name
AND db.accounting_date = l_date
UNION ALL
SELECT
id_specific,
NVL ( accounted_cr, 0 ) - NVL ( accounted_dr, 0 ) sum_spec
FROM
gl_gl_je_lines l,
gl_gl_je_headers h,
(SELECT
specific2.id id_specific,
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 BETWEEN '021999999' AND '023999999'
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
h.ledger_id = 2021
AND h.actual_flag = 'A'
AND h.currency_code = 'KZT'
AND h.je_header_id = l.je_header_id
AND l.code_combination_id = cc.code_combination_id
AND l.ledger_id = h.ledger_id
AND l.status = 'P'
AND l.period_name = l_period_name
AND l.effective_date BETWEEN TRUNC ( l_date, 'MM' )
AND l_date
UNION ALL
SELECT
id_specific,
NVL ( begin_balance_cr, 0 ) - NVL ( begin_balance_dr, 0 ) sum_spec
FROM
gl_gl_balances db,
(SELECT
specific2.id id_specific,
code_combination_id,
segment1,
segment2,
segment3,
segment4,
segment7
FROM
apps_gl_code_combinations cc,
xxkkbi_dim_specific specific2
WHERE
chart_of_accounts_id = 50408
AND template_id IS NULL
AND ( segment1 = CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
'02'
ELSE
'03'
END )
AND segment2 LIKE CASE
WHEN
SUBSTR ( l_region, 3, 2 ) = '01'
THEN
SUBSTR ( l_region, 1, 2 ) || '%'
ELSE
l_region
END
AND segment3 BETWEEN '021999999' AND '023999999'
AND segment5 = '0'
AND segment6 = '0000000'
AND segment7 = '1'
AND segment4 = specific2.code
AND specific2.date_end >= l_date
) cc
WHERE
db.code_combination_id = cc.code_combination_id
AND db.ledger_id = 2021
AND db.actual_flag = 'A'
AND db.currency_code = 'KZT'
AND db.period_name = l_period_name
AND segment4 NOT IN (SELECT segment4 FROM temp_2_27)
) t1
GROUP BY t1.id_specific
);
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'END INSERT',
p_rows_count => SQL%ROWCOUNT,
p_rows_date => l_date,
p_oper_descr => l_descr
);
COMMIT;
END LOOP;
END LOOP;
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'END PROCEDURE'
);
RETURN;
EXCEPTION
WHEN
OTHERS
THEN
BEGIN
l_err_code := SQLCODE;
l_err_msg := SUBSTR ( SQLERRM, 1, 2000 );
pkg_fct_log.fct_log_2 (
p_fct_name => l_fct,
p_oper_name => 'EXCEPTION',
p_err_code => l_err_code,
p_err_msg => l_err_msg
);
END;
END kzt_2_27_p;
【问题讨论】:
六天?涉及多少行,您的日志记录是否显示活动和时间?你做了什么来调查它在哪里以及为什么很慢?你确定有什么东西一直在阻止它吗?所有嵌套循环及其插入和其中的子查询都可能被消除并替换为每个表的单个插入,但我怀疑你会发现有人愿意尝试为你重写整个事情。 @AlexPoole,当我刷新收集所有数据的表时,1 分钟内大约有 1 个新行。可以清楚的看到,有很多同类型的嵌套查询。 那么您需要查看各个语句 - 我猜子查询正在杀死每个插入,并且可能会被连接替换。但是您需要摆脱循环并批量执行操作。分组思考,不要从程序(逐行)方法开始。 并且开发人员已经开始(ab)使用CASE
像任何东西一样。
@LalitKumarB - 是的 - 带有易读性复合体的臭铁杆 - 他们应该像 REAL MEN 一样滥用 DECODE
!!!!!
【参考方案1】:
将操作拆分为不同的操作,而不是 将它们全部保存在一个过程中。
ROW-by-ROW
是SLOW-by-SLOW
,利用BULK
处理和
摆脱FOR LOOP
。
调优是一个手动过程,PL/SQL 和 SQL 是不同的引擎。两个引擎之间的每个上下文切换都会产生开销。如果 PL/SQL
代码循环通过一个集合,对集合中的每个项目执行相同的 DML 操作,则可以在一个操作中将整个集合减少 context switches
bulk binding
为 DML 语句。
使用FORALL
语法,它允许我们将集合的内容绑定到单个DML 语句,允许为集合中的每一行运行DML
,而无需每次都进行上下文切换。
如果可能,我希望将每个 INSERT
都作为单独的 SQL。只有您知道环境规范和限制。
【讨论】:
以上是关于优化 PL/SQL 代码 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章