Как распечатать текущее время с DBMS_OUTPUT.PUT_LINE? - PullRequest
0 голосов
/ 22 мая 2018

Я использую следующий код для запуска экспорта данных.

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;

Проблема в том, что экспорт занимает слишком много времени.Это займет 25 минут с этим кодом SQL.Размер схемы составляет 1,8 ГБ.

И я хотел бы узнать, сколько времени занимает выполнение отдельных шагов.Вот почему я хочу вставить метку времени после каждого шага процесса.Затем я вижу, сколько нужно отдельных шагов.

Я пометил код метки времени с помощью (>>>> <<<<) в коде. </p>

Метка времени не обновляется.время.Мне нужно ТЕКУЩЕЕ время после каждого процесса.Вы можете мне помочь?

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

Вот пример 'CURRENT_TIMESTAMP'

curDateTime  TIMESTAMP := CURRENT_TIMESTAMP ;
DBMS_OUTPUT.PUT_LINE('CUR TIME '|| curDateTime);
0 голосов
/ 22 мая 2018

Если процедура, которую вы запускаете, занимает много времени, 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 минут, так что - это то, что вынужно расследовать.Это означает, что вам не нужно ждать завершения основной процедуры - отмените ее и начните работать над узким местом.Как только вы это исправите, запустите все снова.

0 голосов
/ 22 мая 2018

В вашем коде вы устанавливаете значение 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'));
...