【问题标题】:How can print out the current time with DBMS_OUTPUT.PUT_LINE?如何使用 DBMS_OUTPUT.PUT_LINE 打印出当前时间?
【发布时间】:2018-10-31 22:03:12
【问题描述】:

我使用以下代码执行导出数据泵。

set serveroutput on;
DECLARE
  ind NUMBER;              -- Loop index
  h1 NUMBER;               -- Data Pump job handle
  percent_done NUMBER;     -- Percentage of job complete
  job_state VARCHAR2(30);  -- To keep track of job state
  le ku$_LogEntry;         -- For WIP and error messages
  js ku$_JobStatus;        -- The job status from get_status
  jd ku$_JobDesc;          -- The job description from get_status
  sts ku$_Status;          -- The status object returned by get_status
  >>>>>>>>>>>>>>v_systimestamp TIMESTAMP := SYSTIMESTAMP;<<<<<<<<<<<<<<

BEGIN

  h1 := DBMS_DATAPUMP.OPEN('EXPORT','SCHEMA',NULL,'EXAMPLE3','LATEST');

  DBMS_DATAPUMP.ADD_FILE(h1, 'dumpfile.dmp', 'EXPORT_DIRECTORY', NULL, DBMS_DATAPUMP.KU$_FILE_TYPE_DUMP_FILE, 1);

  DBMS_DATAPUMP.METADATA_FILTER(h1,'SCHEMA_EXPR','IN (''SchemaName'')');

  DBMS_DATAPUMP.START_JOB(h1);



  percent_done := 0;
  job_state := 'UNDEFINED';
  while (job_state != 'COMPLETED') and (job_state != 'STOPPED') loop
             DBMS_OUTPUT.PUT_LINE(v_systimestamp);
    dbms_datapump.get_status(h1,
           dbms_datapump.ku$_status_job_error +

           dbms_datapump.ku$_status_job_status +
           dbms_datapump.ku$_status_wip,-1,job_state,sts);
    js := sts.job_status;

-- If the percentage done changed, display the new value.

    if js.percent_done != percent_done
    then

      dbms_output.put_line('*** Job percent done = ' ||
                           to_char(js.percent_done));
      percent_done := js.percent_done;
    end if;

-- If any work-in-progress (WIP) or error messages were received for the job,
-- display them.

   if (bitand(sts.mask,dbms_datapump.ku$_status_wip) != 0)
    then

      le := sts.wip;
    else
      if (bitand(sts.mask,dbms_datapump.ku$_status_job_error) != 0)
      then
        le := sts.error;
      else
        le := null;
      end if;
    end if;
    if le is not null
    then
      ind := le.FIRST;
      while ind is not null loop
        >>>>>>>>>>>>>>DBMS_OUTPUT.PUT_LINE(v_systimestamp);<<<<<<<<<<<<<<
        dbms_output.put_line(le(ind).LogText);
        ind := le.NEXT(ind);
      end loop;
    end if;
  end loop;

-- Indicate that the job finished and detach from it.

  dbms_output.put_line('Job has completed');
  dbms_output.put_line('Final job state = ' || job_state);
  dbms_datapump.detach(h1);
END;

问题是导出时间过长。使用此 SQL 代码需要 25 分钟。架构的大小为 1.8 GB。

我想知道每个步骤需要多少时间。这就是为什么我想在每个流程步骤之后插入一个时间戳。然后我可以看到各个步骤需要多长时间。

我已经在代码中用 (>>>>

时间戳没有更新时间。我需要每个过程之后的当前时间。你能帮帮我吗?

【问题讨论】:

  • 使用DBMS_OUTPUT.PUT_LINE(SYSTIMESTAMP);
  • 使用DBMS_OUTPUT.PUT_LINE(systimestamp); 打印当前时间戳。
  • 如果您想使用像v_systimestamp 这样的变量,那么您需要在每次使用前将其设置为当前时间。或者直接使用systimestamp,尽管我会对其应用格式,因为默认值可能并不理想。或者,有一个日志记录过程,它使用default on null 时间戳列写入日志表。

标签: database oracle plsql timestamp oracle-sqldeveloper


【解决方案1】:

在您的代码中,您在脚本的开头设置了 v_systimestamp 的值 - 这在脚本运行期间不会改变。您可以在登录之前重置该值:

v_systimestamp TIMESTAMP := SYSTIMESTAMP
DBMS_OUTPUT.PUT_LINE(v_systimestamp)

或在您要监控的每个部分之前和之后执行以下操作(不需要变量):

DBMS_OUTPUT.PUT_LINE('Time Started: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS'));

DBMS_OUTPUT.PUT_LINE('Time Ended: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS'));

【讨论】:

    【解决方案2】:

    此处以“CURRENT_TIMESTAMP”为例

    curDateTime  TIMESTAMP := CURRENT_TIMESTAMP ;
    DBMS_OUTPUT.PUT_LINE('CUR TIME '|| curDateTime);
    

    【讨论】:

      【解决方案3】:

      如果您运行的程序需要很长时间,DBMS_OUTPUT.PUT_LINE 将无济于事。好吧,它会显示一些东西,但是 - 当您使用循环时,根据迭代次数,DBMS_OUTPUT 可能会用完缓冲区大小或超过 SQL*Plus 中的可见行数(如果您使用它),您将丢失部分输出。

      此外,在程序完成之前,您不会看到DBMS_OUTPUT.PUT_LINE 的单个字母

      因此,我建议您使用另一种方法 - 一种简单的日志记录,它需要一个表、一个序列和一个(自治事务)过程。这是脚本:

      CREATE TABLE a1_log
      (
         id      NUMBER,
         datum   DATE,
         descr   VARCHAR2 (500)
      );
      
      CREATE SEQUENCE seqlognap START WITH 1 INCREMENT BY 1;
      
      CREATE OR REPLACE PROCEDURE a1_p_log (par_descr IN VARCHAR2)
      IS
         PRAGMA AUTONOMOUS_TRANSACTION;
      BEGIN
         INSERT INTO a1_log
            SELECT seqlognap.NEXTVAL, SYSDATE, par_descr FROM DUAL;
      
         COMMIT;
      END a1_p_log;
      

      然后将 A1_P_LOG 调用放入您自己的过程中;像

      begin
        a1_p_log('selecting from a large table');
        select ... into ... from ...;
      
        a1_p_log('entering the loop');
        while ... loop
          a1_p_log('doing something');
        end loop;
      
        a1_p_log('the end');
      end;
      

      这就是自治事务很重要的地方 - 它会将插入提交到日志表中(不影响主事务),因此您可以(当然在另一个会话中)跟踪执行,只需重复发出即可

        SELECT *
          FROM a1_log
      ORDER BY id;
      

      它会显示(想象的例子):

      1   22.05.2018 18:13:00    selecting from a large table
      2   22.05.2018 18:20:07    entering the loop
      3   22.05.2018 18:20:07    doing something
      4   22.05.2018 18:20:08    doing something
      5   22.05.2018 18:20:09    doing something
      6   22.05.2018 18:20:10    the end
      

      您会看到第 1 步需要 7 分钟才能执行,所以 - 这就是您需要调查的内容。这意味着您不必等待主程序完成 - 取消它并开始处理瓶颈。修复后,再次运行所有内容。

      【讨论】:

      • 非常感谢您的帮助。非常感谢大家。但我在 SQL 方面没有太多经验。我喜欢你的回答和解决方案。但是我必须在第二个代码中输入什么?我应该如何编写循环?此过程创建一个表。在每个过程之后我是否删除了表格?这会是个问题吗?因为当我导出包含 100 个表的模式时。那么export deump-file里面有101个Tables?我说的对吗?
      • 不客气。是的,该表 (A1_LOG) 将是导出的一部分。 EXPDP 有一个exclude 表的选项,因此您可以根据需要这样做。或者干脆忽略它,也可以选择在目标架构中进行进度日志记录。
      • 非常感谢。我有另一个问题。有没有办法用java应用程序在进度栏中显示数据泵的进度?我认为问题在于数据泵程序完全在 oracle 上运行。但也许有可能做到这一点?
      • 我不知道,抱歉。
      • 如果你问我,@alex,那么:不,我没有做过任何基准测试。但我确实有一些需要一段时间才能完成的程序(比如 2 小时)。我无法使用 DBMS_OUTPUT.PUT_LINE 跟踪它的执行,因为在过程完成之前会显示 nothing。这不是我想要的——我希望能够看到程序的哪一部分已经执行,那段特定的代码花费了多少时间,它影响了多少行(通过 SQL%ROWCOUNT)并将所有这些信息写入我的记录表。我可以随时查询并了解当前发生了什么。
      猜你喜欢
      • 2012-05-13
      • 1970-01-01
      • 2018-04-18
      • 1970-01-01
      • 1970-01-01
      • 2013-12-10
      • 2016-04-03
      • 1970-01-01
      • 2019-08-29
      相关资源
      最近更新 更多