Как узнать время выполнения Ref Cursor в процедуре?

Я использую Ref Cursor в качестве выходного параметра для процедуры PLSQL. Мне нужно поддерживать точное время начала и окончания процесса в таблице журнала.

Фиктивный код ниже:

Procedure(P1 IN NUMBER, P_REF_CUR OUT SYS_REFCURSOR)
IS
V_TS TIMESTAMP;
BEGIN
V_TS := SYSTIMESTAMP;
<Business logic here to generate SELECT query for Ref Cursor...>;

OPEN P_REF_CUR FOR <SELECT QUERY>;

INSERT INTO LOG_TABLE(ID, STR_TIME,END_TIME,..) VALUES 
(1,V_TS,SYSTIMESTAMP,...);
END;

Запрос на выбор для Ref Cursor иногда занимает 2-3 минуты, но в таблице журнала я вижу разницу между STR_TIME и END_TIME всего в несколько секунд.

Как я могу зафиксировать общее время, затрачиваемое процедурой, включая время выполнения запроса?


person Kapil    schedule 27.03.2018    source источник
comment
Что именно вы подразумеваете под общим «временем выполнения запроса»? Предположительно, 2-3 минуты включают в себя выборку и отображение всех данных, возможно, с дополнительным запаздыванием в сети в зависимости от используемых инструментов. Я предполагаю, что вам нужно соответствующее общее время для открытия-выборки-закрытия и обработки всего набора результатов ?.   -  person Alex Poole    schedule 27.03.2018
comment
Эта процедура вызывается инструментом отчетности для создания отчета. Создание этого отчета занимает некоторое время, которое в первую очередь является временем выполнения запроса, которое я хочу найти и зарегистрировать в своей таблице журнала. Если я EXECUTE SELECT COUNT (*) INTO VAR FROM (CURSOR SELECT QUERY), это даст мне время выполнения запроса?   -  person Kapil    schedule 27.03.2018


Ответы (3)


Вы не можете сказать изнутри процедуры. OPEN FOR инструкция:

... связывает переменную курсора с запросом, выделяет ресурсы базы данных для обработки запроса, идентифицирует набор результатов и помещает курсор перед первой строкой набора результатов.

Все, что вы можете измерить в своей процедуре, - это сколько времени потребуется для генерации текста запроса и сколько времени потребуется, чтобы открыть курсор. Затем процедура заканчивается, и вызывающий принимает на себя указатель OUT ref. Отсюда вы ничего не видите о том, что происходит с курсором.

Вызывающий чем (предположительно) извлекает данные, что занимает большую часть времени; но может также выполнять другую обработку. Вам нужно, чтобы вызывающий объект регистрировал время между вызовом вашей процедуры и закрытием курсора ref, когда он закончил с ним, но это все равно будет включать любую дополнительную обработку, которую он выполняет, поэтому вы не можете отделить, сколько на самом деле происходит от обработка и выборка курсорных запросов.

Если это достаточно близко, у вас потенциально может быть вторая процедура, которая закрывает курсор и регистрирует время, если вы не хотите, чтобы вызывающий абонент беспокоился об этом. Вы можете заставить курсор «открыть» записывать время начала в переменной сеанса (делая пакет с сохранением состояния), а процедура «закрытия» извлекает это и вставляет запись в журнал; или попросите «open» выполнить начальную вставку в таблицу регистрации с нулевым временем окончания, а затем «закрыть» обновить эту запись с фактическим временем окончания. Но опять же, это только приблизительное значение.

если вы действительно хотите сделать все это в этой процедуре, вам придется выполнять всю обработку запросов внутри нее, что, вероятно, означает массовый сбор курсора в коллекцию и использование этого типа коллекции в качестве параметра OUT , настраивая вызывающего абонента, чтобы перебирать его вместо курсора. Это, конечно, также требует дополнительных затрат на память, поэтому может быть непрактичным.

person Alex Poole    schedule 27.03.2018

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

person William Robertson    schedule 27.03.2018

Вы можете попытаться разделить эту процедуру на две комплексные процедуры и применить set timing on:

SQL> create or replace package myPkg is
        procedure pr1(P1 IN NUMBER);
        procedure pr2(P_REF_CUR OUT SYS_REFCURSOR);
end;
/

SQL> create or replace package body myPkg is
    v_ts  timestamp;
  procedure pr1(P1 IN NUMBER) is
  begin
    v_ts := SYSTIMESTAMP;
    <Business logic here to generate SELECT query for Ref Cursor...>;  
  end;

  procedure pr2(P_REF_CUR OUT SYS_REFCURSOR) is
  begin
    open P_REF_CUR for <SELECT QUERY>;
    insert into log_table(ID, STR_TIME,END_TIME,..) values(1,V_TS,SYSTIMESTAMP,...);  
  end;  
end;
/

SQL> set timing on;
SQL> var v_p1 number:=107;
SQL> var v_rc refcursor;
SQL> exec myPkg.pr1( :v_p1 );

PL/SQL procedure successfully completed

Executed in 152,25 seconds

SQL> exec myPkg.pr2( :v_rc );

PL/SQL procedure successfully completed

Executed in 12,34 seconds

SQL> print v_rc;
person Barbaros Özhan    schedule 27.03.2018
comment
Это все равно скажет вам, сколько времени потребовалось open, а не сколько времени потребовалось для получения всех данных? Также вашему V_TS нужен тип данных, и он будет установлен только при создании экземпляра пакета, поэтому вам нужно сбрасывать его для каждого вызова пары процедур - предположительно внутри pr1? - person Alex Poole; 27.03.2018
comment
@AlexPoole, большое спасибо, Алекс, я отредактировал, как ты и предупреждаешь для v_ts. - person Barbaros Özhan; 27.03.2018