F.42. pgpro_application_info — перенос приложений, использующих пакет DBMS_APPLICATION_INFO #

pgpro_application_info — это расширение, предназначенное для помощи разработчикам, которые переносят приложения, использующие пакет DBMS_APPLICATION_INFO, из Oracle в Postgres Pro. Администраторы баз данных также могут использовать его в качестве дополнительного источника данных при анализе производительности, а разработчики — для отладки.

Расширение pgpro_application_info создаёт процедуры и функции, которые позволяют приложениям сообщать о своём состоянии, выполняемых действиях и ходе их выполнения. Администратор БД может получить доступ к этой информации через специальные представления.

Типичная последовательность действий клиента, поддерживающего работу с pgpro_application_info, будет выглядеть следующим образом (в данном примере библиотекарь хочет подсчитать все слова «the» в библиотеке):

  1. При подключении к базе данных клиент сообщает, что он — Librarian, и запускает приложение сканера, которое, в свою очередь, сообщает, что оно — модуль Book Scanner и что в данный момент оно пытается выполнить операцию Book Scanning, чтобы найти все вхождения слова «the» в 18042 книгах, при этом на данный момент просканировано 0 книг.

  2. Просканировав несколько книг, приложение обновляет информацию, чтобы отразить ход выполнения операции.

  3. Когда сканирование завершено, приложение сообщает об этом и меняет выполняемое действие на Idle (или NULL).

F.42.1. Установка #

Расширение pgpro_application_info включено в состав Postgres Pro Enterprise как стандартное расширение. Чтобы задействовать pgpro_application_info, выполните следующие действия:

  1. Добавьте имя библиотеки в переменную shared_preload_libraries в файле postgresql.conf:

    shared_preload_libraries = 'pgpro_application_info'
  2. Перезагрузите сервер баз данных, чтобы изменения вступили в силу.

    Примечание

    Чтобы убедиться, что библиотека установлена правильно, вы можете выполнить следующую команду:

    SHOW shared_preload_libraries;
  3. Создайте расширение, выполнив следующий запрос:

    CREATE EXTENSION pgpro_application_info;

F.42.2. Использование #

pgpro_application_info работает со следующими основными классами данных:

  • Информация о приложении: имя текущего модуля, выполняемое действие и описание клиента. Администратор БД может получить доступ к информации об активных клиентах и их действиях через представление V_SESSION.

  • Информация о длительных операциях: текстовые описания и комментарии, отчёт о ходе операции и, при необходимости, ссылка на обрабатываемый объект базы данных. Администратор БД может получить доступ к информации о длительных операциях через представление V_SESSION_LONGOPS, которое помимо данных, отправленных клиентом, содержит временные метки начала и последнего обновления операции, а также ожидаемое оставшееся время выполнения.

Примечание

Обратите внимание, что в Oracle текстовые параметры DBMS_APPLICATION_INFO, передаваемые пользователем, имеют разные ограничения по длине до 64 байт, а в pgpro_application_info для удобства все они имеют одинаковое ограничение — 64 байта. Более длинные значения усекаются.

F.42.2.1. Информация о приложении #

Для передачи информации о приложении в pgpro_application_info предусмотрены следующие процедуры:

CREATE PROCEDURE DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info TEXT) #

Передаёт информацию о клиенте. Обычно это имя клиента или более сложное описание, но, строго говоря, это может быть любой текст, передаваемый пользователем.

CREATE PROCEDURE DBMS_APPLICATION_INFO.SET_ACTION(action_name TEXT) #

Передаёт имя действия, выполняемого в данный момент в текущем модуле.

CREATE PROCEDURE DBMS_APPLICATION_INFO.SET_MODULE(module_name TEXT, action_name TEXT DEFAULT NULL) #

Передаёт имя выполняемого в данный момент модуля (программы) и действия. По завершении программы рекомендуется вызвать процедуру с именем следующего модуля, если он есть, или с NULL в противном случае.

CREATE PROCEDURE DBMS_APPLICATION_INFO.READ_CLIENT_INFO(OUT client_info TEXT) #

Возвращает информацию о клиенте, переданную ранее процедурой SET_CLIENT_INFO в текущем сеансе.

CREATE PROCEDURE DBMS_APPLICATION_INFO.READ_MODULE(OUT module_name TEXT, OUT action_name TEXT) #

Возвращает информацию о модуле, переданную ранее процедурой SET_MODULE, и информацию о действии, переданную процедурой SET_MODULE или SET_ACTION в текущем сеансе.

F.42.2.1.1. Представление V_SESSION #

Представление V_SESSION содержит информацию обо всех активных сеансах, информация о которых была передана процедурами pgpro_application_info, о подключённых клиентах, модулях и выполняемых действиях. Представление содержит одну строку для каждого отдельного сеанса. Когда сеанс впервые сообщает информацию о себе, создаётся соответствующая запись в представлении. Каждая строка существует в течение соответствующего сеанса, поэтому после перезапуска сервера представление пустое. Столбцы представления показаны в Таблице F.33. Для удобства в Postgres Pro также поддерживается эквивалентное представление с названием V$SESSION, привычное для пользователей Oracle и содержащее ту же информацию. Однако обратите внимание, что улучшенная совместимость с Oracle, обеспечиваемая этой альтернативой, является отклонением от стандарта SQL и поэтому делает код менее переносимым.

CREATE FUNCTION DBMS_APPLICATION_INFO.READ_V_SESSION(
    OUT SID INTEGER,
    OUT DBNAME TEXT,
    OUT MODULE TEXT,
    OUT ACTION TEXT,
    OUT CLIENT_INFO TEXT
)
CREATE VIEW V_SESSION AS SELECT * FROM DBMS_APPLICATION_INFO.READ_V_SESSION();

Таблица F.33. Столбцы V_SESSION

ИмяОписание
SIDID сеанса, PID
DBNAMEИмя базы данных, к которой подключён сеанс. Если вы хотите получить записи только для текущей базы данных, добавьте в запрос следующее условие: WHERE DBNAME=current_database().
MODULEИмя модуля, выполняемого данным сеансом, ранее переданное процедурой SET_MODULE.
ACTIONИмя действия, выполняемого данным сеансом, ранее переданное процедурой SET_MODULE или SET_ACTION.
CLIENT_INFOИнформация о связанном с сеансом клиенте, ранее переданная процедурой SET_CLIENT_INFO.

F.42.2.2. Информация о длительных операциях #

CREATE PROCEDURE DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(
                INOUT RINDEX INTEGER,
                INOUT SLNO INTEGER,
                OP_NAME TEXT DEFAULT NULL,
                TARGET OID DEFAULT 0,
                CONTEXT INTEGER DEFAULT 0,
                SOFAR DOUBLE PRECISION DEFAULT 0,
                TOTALWORK DOUBLE PRECISION DEFAULT 0,
                TARGET_DESC TEXT DEFAULT 'unknown target',
                UNITS TEXT DEFAULT NULL
            )

Процедура SET_SESSION_LONGOPS создаёт новую строку (или изменяет существующую) в представлении V_SESSION_LONGOPS. Каждая строка содержит информацию об одной длительной операции (как правило, выполняемой более 6 секунд): её описание, с какими объектами она работает и ожидаемое оставшееся время выполнения.

  • RINDEX: Индекс строки в представлении V_SESSION_LONGOPS. Чтобы создать новую строку, укажите в нём результат функции DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT(). Когда вы вызываете SET_SESSION_LONGOPS для изменения существующей строки, укажите в индексе значение, возвращённое при предыдущем вызове.

  • SLNO: Служебная информация, сохраняемая между вызовами. Чтобы создать новую строку, установите значение NULL. Когда вы вызываете SET_SESSION_LONGOPS для изменения существующей строки, установите для данного параметра значение, возвращённое при предыдущем вызове.

  • OP_NAME: Краткое описание выполняемой операции, обычно её имя.

  • TARGET: OID объекта, который обрабатывается в ходе длительной операции.

  • CONTEXT: Произвольное число, задаваемое пользователем.

  • SOFAR: Произвольное число, задаваемое пользователем. Обычно это объём уже выполненной работы.

  • TOTALWORK: Произвольное число, задаваемое пользователем. Обычно это общий ожидаемый объём работы.

  • TARGET_DESC: Описание объекта, который обрабатывается в ходе длительной операции (TARGET).

  • UNITS: Наименование единиц, в которых заданы параметры SOFAR и TOTALWORK.

Значения SOFAR и TOTALWORK используются для расчёта оставшегося времени выполнения в представлении V_SESSION_LONGOPS, но допустимыми значениями являются любые числа, поэтому при несогласованности этих значений (например, если оба значения отрицательные или TOTALWORK=0) оставшееся время выполнения рассчитываться не будет.

F.42.2.2.1. Представление V_SESSION_LONGOPS #

Представление V_SESSION_LONGOPS содержит информацию о длительных операциях, переданную ранее процедурой SET_SESSION_LONGOPS. Представление содержит одну строку для каждой отдельной длительной операции. Каждая строка существует до тех пор, пока она не будет перезаписана или не будет остановлен сервер. После перезагрузки сервера представление пустое. Столбцы представления показаны в Таблице F.34. Для удобства в Postgres Pro также поддерживается эквивалентное представление с названием V$SESSION_LONGOPS, привычное для пользователей Oracle и содержащее ту же информацию. Кроме того, в этом представлении столбец P_TIMESTAMP был переименован в TIMESTAMP. Однако обратите внимание, что улучшенная совместимость с Oracle, обеспечиваемая этими альтернативами, является отклонением от стандарта SQL и поэтому делает код менее переносимым.

CREATE FUNCTION DBMS_APPLICATION_INFO.READ_V_SESSION_LONGOPS(
    OUT SID INTEGER,
    OUT SERIAL_N INTEGER,
    OUT DBNAME TEXT,
    OUT OPNAME TEXT,
    OUT TARGET OID,
    OUT TARGET_DESC TEXT,
    OUT SOFAR DOUBLE PRECISION,
    OUT TOTALWORK DOUBLE PRECISION,
    OUT UNITS TEXT,
    OUT START_TIME TIMESTAMP,
    OUT LAST_UPDATE_TIME TIMESTAMP,
    OUT P_TIMESTAMP TIMESTAMP,
    OUT TIME_REMAINING INTEGER,
    OUT ELAPSED_SECONDS INTEGER,
    OUT CONTEXT INTEGER,
    OUT MESSAGE TEXT,
    OUT USERNAME TEXT
)
CREATE VIEW V_SESSION_LONGOPS AS SELECT * FROM DBMS_APPLICATION_INFO.READ_V_SESSION_LONGOPS();

Таблица F.34. Столбцы V_SESSION_LONGOPS

ИмяОписание
SIDИдентификатор сеанса, в котором выполняется длительная операция.
SERIAL_NСиноним SID. Добавлен для совместимости с Oracle.
DBNAMEИмя базы данных, к которой подключён сеанс. Если вы хотите получить строки только для текущей базы данных, добавьте в запрос следующее условие: WHERE DBNAME=current_database().
OPNAMEКраткое описание выполняемой операции, обычно её имя.
TARGETOID объекта, который обрабатывается в ходе длительной операции.
TARGET_DESCОписание объекта, который обрабатывается в ходе длительной операции (TARGET).
SOFARОбъём уже выполненной работы в единицах, указанных в UNITS.
TOTALWORKОбщий ожидаемый объём работы в единицах, указанных в UNITS.
UNITSНаименование единиц, в которых заданы параметры SOFAR и TOTALWORK.
START_TIMEВремя начала выполнения операции (фактически — время создания данной строки)
LAST_UPDATE_TIMEВремя последнего изменения записи об операции.
P_TIMESTAMPСиноним для LAST_UPDATE_TIME. Добавлен для совместимости с Oracle. Для удобства можно использовать другое имя параметра, добавив псевдоним. Например, чтобы создать псевдоним TIMESTAMP, добавьте SELECT P_TIMESTAMP AS TIMESTAMP в определение представления.
TIME_REMAININGОжидаемое оставшееся время выполнения операции (в секундах). Рассчитывается на основе значений SOFAR и TOTALWORK. Оставшееся время выполнения не будет рассчитываться, если эти значения несогласованны, SOFAR=0 или LAST_UPDATE_TIME совпадает с START_TIME.
ELAPSED_SECONDSКоличество секунд, прошедших с начала выполнения операции (создания строки).
CONTEXTЧисло, заданное пользователем в качестве контекста.
MESSAGEСообщение с краткой статистикой о ходе выполнения операции.
USERNAMEИмя пользователя, выполняющего операцию.

F.42.3. Пример #

В нашем простом примере приложение будет действовать от имени ленивого мальчика, считающего ворон:

DO $$
DECLARE
    rindex integer := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT();
    slno integer := NULL;
    total_crows integer := 146;
BEGIN
    CALL DBMS_APPLICATION_INFO.SET_CLIENT_INFO('Lazy boy');
    CALL DBMS_APPLICATION_INFO.SET_MODULE('Crow counter', 'Prepare');

    PERFORM pg_sleep(2);

    CALL DBMS_APPLICATION_INFO.SET_ACTION('Count');

    FOR i IN 1..total_crows LOOP
        CALL DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(
            RINDEX=>rindex,
            SLNO=>slno,
            OP_NAME=>'Counting birds',
            CONTEXT=>42,
            SOFAR=>i,
            TOTALWORK=>total_crows,
            UNITS=>'birds'
        );
        PERFORM pg_sleep(0.4);
    END LOOP;

    CALL DBMS_APPLICATION_INFO.SET_ACTION(NULL);
END$$;

Если запустить этот код в psql и обращаться к V_SESSION и V_SESSION_LONGOPS в другом сеансе, можно получить такие результаты:

postgres=# select * from v_session_longops;
 sid | serial_n | dbname | opname | target | target_desc | sofar | totalwork | units | start_time | last_update_time | p_timestamp | time_remaining | elapsed_seconds | context | message | username
-----+----------+--------+--------+--------+-------------+-------+-----------+-------+------------+------------------+-------------+----------------+-----------------+---------+---------+----------
(0 rows)

postgres=# select * from v_session;
 sid | dbname | module | action | client_info
-----+--------+--------+--------+-------------
(0 rows)

postgres=# select * from v_session;
 sid  |  dbname  |    module    | action  | client_info
------+----------+--------------+---------+-------------
 3721 | postgres | Crow counter | Prepare | Lazy boy
(1 row)

postgres=# select * from v_session;
 sid  |  dbname  |    module    | action | client_info
------+----------+--------------+--------+-------------
 3721 | postgres | Crow counter | Count  | Lazy boy
(1 row)

postgres=# select * from v_session_longops;
 sid  | serial_n |  dbname  |     opname     | target |  target_desc   | sofar | totalwork | units |         start_time         |      last_update_time      |        p_timestamp         | time_remaining | elapsed_seconds | context |               message                | username
------+----------+----------+----------------+--------+----------------+-------+-----------+-------+----------------------------+----------------------------+----------------------------+----------------+-----------------+---------+--------------------------------------+----------
 3721 |     3721 | postgres | Counting birds |      0 | unknown target |    52 |       146 | birds | 2023-05-12 14:24:19.013571 | 2023-05-12 14:24:39.458126 | 2023-05-12 14:24:39.458126 |             36 |              20 |      42 | Counting birds: 52 of 146 birds done | postgres
(1 row)

postgres=# select * from v_session_longops;
 sid  | serial_n |  dbname  |     opname     | target |  target_desc   | sofar | totalwork | units |         start_time         |     last_update_time      |        p_timestamp        | time_remaining | elapsed_seconds | context |               message                | username
------+----------+----------+----------------+--------+----------------+-------+-----------+-------+----------------------------+---------------------------+---------------------------+----------------+-----------------+---------+--------------------------------------+----------
 3721 |     3721 | postgres | Counting birds |      0 | unknown target |    89 |       146 | birds | 2023-05-12 14:24:19.013571 | 2023-05-12 14:24:54.29141 | 2023-05-12 14:24:54.29141 |             22 |              35 |      42 | Counting birds: 89 of 146 birds done | postgres
(1 row)

postgres=# select * from v_session;
 sid  |  dbname  |    module    | action | client_info
------+----------+--------------+--------+-------------
 3721 | postgres | Crow counter | Count  | Lazy boy
(1 row)

postgres=# select * from v_session_longops;
 sid  | serial_n |  dbname  |     opname     | target |  target_desc   | sofar | totalwork | units |         start_time         |      last_update_time      |        p_timestamp         | time_remaining | elapsed_seconds | context |                message                | username
------+----------+----------+----------------+--------+----------------+-------+-----------+-------+----------------------------+----------------------------+----------------------------+----------------+-----------------+---------+---------------------------------------+----------
 3721 |     3721 | postgres | Counting birds |      0 | unknown target |   140 |       146 | birds | 2023-05-12 14:24:19.013571 | 2023-05-12 14:25:14.736656 | 2023-05-12 14:25:14.736656 |              2 |              55 |      42 | Counting birds: 140 of 146 birds done | postgres
(1 row)

postgres=# select * from v_session_longops;
 sid  | serial_n |  dbname  |     opname     | target |  target_desc   | sofar | totalwork | units |         start_time         |      last_update_time      |        p_timestamp         | time_remaining | elapsed_seconds | context |                message                | username
------+----------+----------+----------------+--------+----------------+-------+-----------+-------+----------------------------+----------------------------+----------------------------+----------------+-----------------+---------+---------------------------------------+----------
 3721 |     3721 | postgres | Counting birds |      0 | unknown target |   146 |       146 | birds | 2023-05-12 14:24:19.013571 | 2023-05-12 14:25:17.140533 | 2023-05-12 14:25:17.140533 |              0 |              58 |      42 | Counting birds: 146 of 146 birds done | postgres
(1 row)

postgres=# select * from v_session;
 sid  |  dbname  |    module    | action | client_info
------+----------+--------------+--------+-------------
 3721 | postgres | Crow counter |        | Lazy boy
(1 row)