【问题标题】:Oracle PL SQL Procedure takes long time to complete, after the very last statement in the procedure is processed在处理过程中的最后一条语句之后,Oracle PL SQL 过程需要很长时间才能完成
【发布时间】:2019-05-25 06:56:19
【问题描述】:

我们使用的是 Oracle 11.2.0.4.0。 我们创建了一个过程来更新表中所有可用行的 CLOB 列。

我们有一个 DBMS_OUTPUT.PUT_LINE 语句用于在过程的最后一行打印 SYSDATE。

当我们执行这个过程时,在最后一行打印完 SYSDATE 之后需要很长时间才能完成。

不确定我是否遗漏了什么。任何帮助将不胜感激

我们尝试通过在过程中添加DBMS_OUPUT.PUT_LINE(SYSDATE) 语句来调试/查找痛点来执行过程。

这就是我们执行过程并在最后粘贴输出的方式:

SET TIMING ON
SET SERVEROUTPUT ON

SELECT 'Outside block Start time: ' || to_char(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') OUTSIDEBLOCKSTARTTIME from dual;
DECLARE
  I_LIMIT BINARY_INTEGER;
  I_STR_TO_REPLACE VARCHAR2(200);
  I_REPLACEMENT_STR VARCHAR2(200);
BEGIN
  I_LIMIT := 10000;
  I_STR_TO_REPLACE := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
  I_REPLACEMENT_STR := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';

  P_TEST_CLOB_MASK(
    I_LIMIT => I_LIMIT,
    I_STR_TO_REPLACE => I_STR_TO_REPLACE,
    I_REPLACEMENT_STR => I_REPLACEMENT_STR
  );

END;
/
SELECT 'Outside block End time: ' || to_char(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') OUTSIDEBLOCKENDTIME from dual;

下面是过程的代码:

CREATE OR REPLACE PROCEDURE p_test_clob_mask (
   i_limit             IN   PLS_INTEGER DEFAULT 1000,
   i_str_to_replace    IN   VARCHAR2
         DEFAULT 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890',
   i_replacement_str   IN   VARCHAR2
         DEFAULT 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
)
IS
   CURSOR cur_fetch_cddaddcomphistory
   IS
      SELECT ROWID row_id, ua4cf_cddaddcomphistory ua4cf_cddaddcomphistory
        FROM generic_set11
       WHERE ua4cf_cddaddcomphistory IS NOT NULL;
   l_limit                NUMBER         := 0;
   l_counter              NUMBER         := 0;
   l_rowid                ROWID;
   l_hold_clob            CLOB;
   l_masked_clob          CLOB;
   l_length_clob          NUMBER         := 0;
   l_str_to_replace       VARCHAR2 (500);
   l_replacement_str      VARCHAR2 (500);
   l_overall_start_dt     DATE;
   l_batch_start_dt       DATE           := NULL;
   l_batch_time_taken     NUMBER         := 0;
   l_overall_time_taken   NUMBER         := 0;
BEGIN
   l_overall_start_dt := SYSDATE;
   DBMS_OUTPUT.put_line (   'Overall Start: '
                         || TO_CHAR (l_overall_start_dt,
                                     'DD-MON-RR HH24:MI:SS'
                                    )
                        );
   l_str_to_replace := i_str_to_replace;
   l_replacement_str := i_replacement_str;
   l_limit           := i_limit;

   OPEN cur_fetch_cddaddcomphistory;

   LOOP
      FETCH cur_fetch_cddaddcomphistory
       INTO l_rowid, l_hold_clob;

      EXIT WHEN cur_fetch_cddaddcomphistory%NOTFOUND;
      l_counter := l_counter + 1;
      l_length_clob := DBMS_LOB.getlength (l_hold_clob);
      DBMS_LOB.createtemporary (l_masked_clob, TRUE);
      DBMS_LOB.writeappend (l_masked_clob,
                            l_length_clob,
                            TRANSLATE (l_hold_clob,
                                       i_str_to_replace,
                                       i_replacement_str
                                      )
                           );

      UPDATE generic_set11
         SET ua4cf_cddaddcomphistory = l_masked_clob
       WHERE ROWID = l_rowid;

      IF MOD (l_counter, l_limit) = 0
      THEN
         COMMIT;
      END IF;
   END LOOP;

   CLOSE cur_fetch_cddaddcomphistory;

   COMMIT;
   l_overall_time_taken :=
                        TRUNC (((SYSDATE - l_overall_start_dt) * 24 * 60), 2);
   DBMS_OUTPUT.put_line (   'Overall End: '
                         || TO_CHAR (SYSDATE, 'DD-MON-RR HH24:MI:SS')
                         || ' - Time taken in Mins: '
                         || l_overall_time_taken
                         || ' - Counters: '
                         || l_counter
                        );
END p_test_clob_mask;
/

我们的期望是在最后一个DBMS_OUPUT.PUT_LINE完成后,该过程应该完成。

但经过的时间说 20 多分钟,而根据最后的DBMS_OUPUT.PUT_LINEstatement,所用时间仅为 3 分钟

下面是输出:

OUTSIDEBLOCKSTARTTIME
-------------------------------------------------------
Outside block Start time: 27-DEC-2018 15:33:45

Elapsed: 00:00:00.118
Overall Start: 27-DEC-18 15:33:45
Overall End: 27-DEC-18 15:37:37 - Time taken in Mins: 3.86 - Counters: 138913


PL/SQL procedure successfully completed.

Elapsed: 00:20:19.313

OUTSIDEBLOCKENDTIME
-----------------------------------------------------
Outside block End time: 27-DEC-2018 15:54:04

Elapsed: 00:00:00.095

【问题讨论】:

  • 在我看来,您好像在创建很多临时的CLOBs。如果您使用 DBMS_LOB.FREETEMPORARY 释放它们会有所帮助吗?
  • 另一种想法是在循环外创建一个临时的CLOB,并在每次循环迭代的开始(或结束)删除它。
  • @LukeWoodward 你成功了。我在循环中添加了DBMS_LOB.freetemporary (l_masked_clob);。现在程序在最后一个DBMS_OUTPUT.PUT_LINE 被执行后立即完成谢谢你的帮助。

标签: oracle plsql oracle11g execution-time


【解决方案1】:

在 cmets 中,解决方法是添加该行

    DBMS_LOB.freetemporary(l_masked_clob);

在循环结束时。这确保了使用的临时CLOBs 在使用时被清理。编写的代码导致 Oracle 为循环的每次迭代创建一个新的临时 CLOB,并且很可能在结束时清理所有这些临时 CLOBs(可能数百甚至数千个)阻塞导致延迟。

另一个可能的性能提升可以通过在循环外创建一个临时的LOB,在循环的每次迭代结束时清除它(例如使用DBMS_LOB.erase 或DBMS_LOB.trim),并在循环的结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 1970-01-01
    相关资源
    最近更新 更多