Перейти к содержимому

9 Ход выполнения операций

Примечание

В этой главе мы рассмотрим:

  • инструменты для отслеживания выполнения команд;

  • отслеживание сбора статистики для планировщика;

  • отслеживание хода выполнения резервного копирования;

  • отслеживание выполнения команд CLUSTER и VACUUM FULL;

  • отслеживание выполнения команд CREATE INDEX и REINDEX;

  • отслеживание выполнения команд COPY.

В этой главе мы рассмотрим отдельный набор системных представлений, которые служат индикаторами выполнения различных команд, работа которых может занимать продолжительное время. Выполнение таких команд может требовать значительных ресурсов, создавать нагрузку (например, на подсистему ввода-вывода), конкурировать с соседними процессами и даже блокировать их. Предполагая подобные риски, администратор должен заранее планировать выполнение таких операций и иметь инструменты, которые позволяют отслеживать ход их выполнения и давать представление о том, когда они будут завершены. Все инструменты, рассматриваемые в этой главе, являются представлениями и показывают состояние на момент обращения аналогично pg_stat_activity и pg_locks. Эта статистика требуется в основном в особых случаях, возникающих при эксплуатации, и может выводиться в пользовательских интерфейсах средств управления PostgreSQL. В меньшей степени она подходит для накопления и отображения в системах мониторинга.

Несмотря на большое количество потенциально долгих команд, СУБД представляет инструменты отслеживания только небольшой части из них:

  • pg_stat_progress_vacuum — выполнение операций очистки и автоочистки;

  • pg_stat_progress_analyze — выполнение сбора статистики для планировщика;

  • pg_stat_progress_basebackup — выполнение операций резервного копирования;

  • pg_stat_progress_cluster — выполнение команд CLUSTER и VACUUM FULL;

  • pg_stat_progress_create_index — выполнение команд CREATE INDEX и REINDEX;

  • pg_stat_progress_copy — выполнение команд COPY.

Представление pg_stat_progress_vacuum подробно рассмотрено в главе 8, посвященной очистке, поэтому здесь мы не будем рассматривать его снова.

Все представления показывают выполняющиеся команды, которые обычно запускаются при необходимости вручную (за исключением автоочистки). Также вероятно, что в последующих версиях СУБД будет расширяться поддержка команд и будут появляться новые похожие представления.

9.1. Представление pg_stat_progress_analyze

При исполнении запроса СУБД следует наиболее оптимальному с точки зрения использования ресурсов плану выполнения, выбранному планировщиком из множества возможных планов. Для оценки планов используется статистика, описывающая данные, хранящиеся в таблицах, и от ее точности зависит качество выбранного плана. Собираемая статистика отражается в системном представлении pg_stats1, основанном на таблице pg_statistic2. В процессе эксплуатации СУБД количественные и качественные характеристики данных могут и будут меняться, и статистика планировщика в pg_statistics будет неизбежно устаревать. В условиях изменяющихся данных очень важно регулярно обновлять статистику: в противном случае выбираемые на основе устаревшей информации планы будут неэффективными, что приведет к избыточному использованию ресурсов и увеличению времени выполнения.

Статистика обычно собирается рабочими процессами автоочистки, но у администратора есть возможность запустить сбор принудительно (с помощью команды ANALYZE3 или VACUUM) и либо дождаться его окончания, либо оценить, сколько времени он займет.

Это может понадобиться в разных ситуациях:

  • после восстановления из логической резервной копии (сделанной с помощью pg_dump) или после загрузки данных с помощью команды COPY нужно собрать начальную статистику, поскольку ее не существовало вообще;

  • после изменения параметра default_statistics_target4, который ограничивает объем анализируемых и собираемых данных;

  • прежде чем начинать глубже исследовать проблему производительности отдельного запроса с помощью EXPLAIN5, можно предварительно убедиться, что статистика актуальна;

  • после обновления версии СУБД с помощью утилиты pg_upgrade6, поскольку при такой процедуре статистика планировщика не переносится.

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

  • pid — идентификатор процесса в операционной системе;

  • datid, datname — идентификатор и имя базы данных, к которой выполнено подключение;

  • relid — идентификатор таблицы, в которой выполняется сбор статистики;

  • phase — фаза сбора статистики:

— initializing — подготовка к сканированию таблицы;

— acquiring sample rows — получение случайной выборки строк для анализа;

— acquiring inherited sample rows — получение выборки строк из дочерних таблиц;

— computing statistics — вычисление статистики на основе выбранного набора строк;

— computing extended statistics — вычисление расширенной статистики;

— finalizing analyze — завершение работы, обновление pg_class;

  • sample_blks_total — общее количество блоков в случайной выборке, необходимой для вычисления статистики;

  • sample_blks_scanned — общее количество уже просканированных блоков;

  • ext_stats_total — количество объектов расширенной статистики;

  • ext_stats_computed — количество вычисленных объектов расширенной статистики, увеличивается только в фазе computing extended statistics;

  • child_tables_total — общее количество дочерних таблиц, в случае сбора статистики в секционированных таблицах;

  • child_tables_done — количество просканированных дочерних таблиц, увеличивается только в фазе acquiring inherited sample rows;

  • current_child_table_relid — идентификатор дочерней таблицы, сканируемой в данный момент; содержит актуальное значение только в фазе acquiring inherited sample rows.

Исходные данные из представления могут быть не очень понятны, поэтому для большей информативности имеет смысл провести некоторую обработку: транслировать идентификаторы в имена, перевести блоки в байты и взять дополнительную информацию из pg_stat_activity, соединив представления по полю pid.

В тестовом окружении довольно сложно поймать автоматически сбор статистики, поэтому запрос можно выполнить с помощью \watch 1 и в соседнем сеансе запустить команду ANALYZE. В первом сеансе появится подобный вывод:

# SELECT
    a.pid, now() - a.xact_start AS xact_age,
    p.datname, p.relid::regclass AS relation,
    a.state, a.wait_event_type ||'.'|| a.wait_event AS wait_event,
    p.phase,
    pg_size_pretty(p.sample_blks_total * (
        SELECT current_setting('block_size')::int )) AS sample_size,
    round(100 * p.sample_blks_scanned /
        greatest(p.sample_blks_total,1), 2) AS "scanned,%",
    p.ext_stats_total ||'/'|| p.ext_stats_computed AS "ext_total/done",
    p.child_tables_total ||'/'|| p.child_tables_done AS "child_total/done",
    current_child_table_relid::regclass AS child_in_progress,
    a.query
  FROM pg_stat_progress_analyze p
  INNER JOIN pg_stat_activity a ON p.pid = a.pid
  ORDER BY now() - a.xact_start DESC;
-[ RECORD 1 ]-----+----------------------
pid               | 536666
xact_age          | 00:00:07.660563
datname           | pgbench
relation          | pgbench_accounts
state             | active
wait_event        | IO.DataFileRead
phase             | acquiring sample rows
sample_size       | 522 MB
scanned,%         | 85.00
ext_total/done    | 0/0
child_total/done  | 0/0
child_in_progress | -
query             | ANALYZE;

Команда ANALYZE выполняется семь секунд, для подсчета статистики нужно получить выборку размером 522 МБ, и на данный момент просканировано уже 85 %. В данном примере через пару секунд сканирование будет закончено и начнется фаза подсчета статистики. Для более сложных случаев с секционированными таблицами или расширенной статистикой есть дополнительные поля с уточняющей информацией.

9.2. Представление pg_stat_progress_basebackup

Резервное копирование является одной из регулярных задач при эксплуатации производственных СУБД и в зависимости от размеров БД и характеристик оборудования может занимать значительное время. При использовании утилиты pg_basebackup7 выполняется полное копирование файлов данных и необходимых WAL-журналов (для их передачи может запускаться дополнительный процесс walsender). Это создает значительную нагрузку на дисковую подсистему и может замедлить выполнение конкурентных запросов. В случае нехватки ресурсов и негативного влияния на производительность администратору важно представлять, как долго выполняется и как скоро закончится резервное копирование. Отслеживание встроено в саму утилиту pg_basebackup (параметры -P, --progress), но следить за ходом выполнения можно и со стороны СУБД с помощью представления pg_stat_progress_basebackup.

Каждая строка представления соответствует отдельному процессу резервного копирования и содержит следующую информацию:

  • pid — идентификатор процесса в операционной системе;

  • phase — фаза резервного копирования:

— initializing — подготовка к резервному копированию;

— waiting for checkpoint to finish — walsender ждет завершения контрольной точки;

— estimating backup size — walsender подсчитывает размер файлов БД для передачи;

— streaming database files — walsender передает данные;

— waiting for wal archiving to finish — walsender ожидает завершения архивирования сегментов WAL-журнала;

— transferring wal files — walsender передает сегменты WAL-журнала, созданные непосредственно в процессе резервного копирования;

  • backup_total — общий объем данных, который будет передан. Значение вычисляется перед резервным копированием и является приблизительной оценкой, поскольку содержимое каталогов данных может измениться в процессе копирования. Если передаваемый объем данных начинает превышать рассчитанное значение, поле устанавливается в backup_streamed. Значение будет отсутствовать (NULL), если расчет оценки в pg_basebackup отключен (параметр --no-estimate-size);

  • backup_streamed — объем переданных данных, увеличивается только в фазах streaming database files и transferring wal files;

  • tablespaces_total — общее количество табличных пространств, которые будут переданы;

  • tablespaces_streamed — количество уже переданных табличных пространств, увеличивается только в фазе streaming database files.

Чтобы увидеть какие-либо результаты, стоит выполнить приведенный ниже запрос с помощью \watch 1, запустив в соседнем терминале резервное копирование. Поскольку полученная резервная копия нам не понадобится, ее запись можно направить в /dev/null:

# pg_basebackup -P -R -X none -c fast -Ft -h 127.0.0.1 -U postgres -D - > /dev/null

Пока резервное копирование выполняется, в сеансе с запросом к pg_stat_progress_basebackup будет выводиться ход его выполнения:

# SELECT
    a.pid,
    host(a.client_addr) AS started_from,
    to_char(backend_start, 'YYYY-MM-DD HH24:MI:SS') AS started_at,
    now() - backend_start AS duration,
    a.state, a.wait_event_type ||'.'|| a.wait_event AS waiting,
    p.phase,
    pg_size_pretty(p.backup_total) AS size_total,
    pg_size_pretty(p.backup_streamed) AS sent,
    round(100 * p.backup_streamed / greatest(p.backup_total,1), 2) AS "sent,%",
    p.tablespaces_total ||'/'|| p.tablespaces_streamed AS "ts_total/streamed"
  FROM pg_stat_progress_basebackup p
  INNER JOIN pg_stat_activity a ON p.pid = a.pid
  ORDER BY now() - backend_start DESC;
-[ RECORD 1 ]--------------+-------------------------
pid                        | 545355
started_from               | 127.0.0.1
started_at                 | 2023-03-06 04:43:41
duration                   | 00:00:36.700719
state                      | active
waiting                    | IO.BaseBackupRead
phase                      | streaming database files
size_total                 | 713 MB
sent                       | 623 MB
sent,%                     | 87.00
ts_total/streamed          | 1/0

Из приведенного фрагмента видно, что резервное копирование длится чуть больше 30 секунд, клиенту отправлена бóльшая часть содержимого БД, копирование выполнено на 87 % и уже подходит к завершению. Из представления pg_stat_activity взяты поле state и маркер ожидания, который в большинстве случаев будет показывать ожидания ввода-вывода, поскольку процесс копирует файлы данных и не использует блокировки.

9.3. Представление pg_stat_progress_cluster

Команды CLUSTER8 и VACUUM FULL9 используются для пересоздания таблиц. Они потребляют много ресурсов и устанавливают исключительную блокировку, запрещающую доступ к обрабатываемым таблицам. При неаккуратном использовании такие команды могут легко заблокировать работу приложений вплоть до своего завершения, поэтому администратору требуется инструмент, позволяющий отслеживать ход их выполнения. Для этого в СУБД есть представление pg_stat_progress_cluster, где каждая строка содержит информацию об отдельной операции со следующим набором полей:

  • pid — идентификатор процесса в операционной системе;

  • datid, datname — идентификатор и имя базы данных, в которой выполняется операция;

  • relid — идентификатор пересоздаваемой таблицы;

  • command — выполняемая команда, CLUSTER или VACUUM FULL;

  • phase — фаза операции:

— initializing — подготовка к сканированию таблицы;

— seq scanning heap — последовательное сканирование таблицы;

— index scanning heap — команда CLUSTER выполняет индексное сканирование таблицы;

— sorting tuples — команда CLUSTER выполняет сортировку строк;

— writing new heap — выполняется запись данных в новый файл таблицы;

— swapping relation files — выполняется подмена старых файлов новыми;

— rebuilding index — перестроение индексов;

— performing final cleanup — очистка и завершение работы;

  • cluster_index_relid — идентификатор индекса для команды CLUSTER;

  • heap_tuples_scanned — общее количество просканированных строк в таблице, изменяется только на стадиях последовательного или индексного сканирования и записи новой таблицы;

  • heap_tuples_written — общее количество записанных строк в таблице, изменяется только на стадиях последовательного или индексного сканирования и записи новой таблицы;

  • heap_blks_total — общее количество блоков в таблице на начало последовательного сканирования таблицы;

  • heap_blks_scanned — общее количество просканированных блоков, изменяется только на этапе последовательного сканирования таблицы;

  • index_rebuild_count — общее количество перестроенных индексов, изменяется только на этапе перестроения индексов.

На основе перечисленных полей легко понять, на каком этапе находится выполнение команды, и оценить ход выполнения. Для большей информативности также имеет смысл соединить представление с pg_stat_activity и провести некоторую обработку.

Для получения осмысленного результата запроса в соседнем терминале нужно запустить команду CLUSTER или VACUUM FULL:

# VACUUM FULL pgbench_accounts;

Тогда в сеансе с запросом к pg_stat_progress_cluster можно будет увидеть следующий вывод:

# SELECT
    a.pid,
    now() - a.xact_start AS xact_age,
    p.datname,
    p.relid::regclass AS relation,
    p.cluster_index_relid::regclass AS index,
    a.state,
    (SELECT count(distinct l.pid) FROM pg_locks l
      WHERE l.relation = p.relid AND NOT l.granted) AS blocked_total,
    a.wait_event_type ||'.'|| a.wait_event AS wait_event,
    p.phase,
    pg_size_pretty(p.heap_blks_total * (
        SELECT current_setting('block_size')::int)) AS size_total,
    round(100 * p.heap_blks_scanned /
        greatest(p.heap_blks_total,1), 2) AS "scanned,%",
    coalesce(p.heap_tuples_scanned, 0) AS tuples_scanned,
    coalesce(p.heap_tuples_written, 0) AS tuples_written,
    a.query
  FROM pg_stat_progress_cluster p
  INNER JOIN pg_stat_activity a ON p.pid = a.pid
  ORDER BY now() - a.xact_start DESC;
-[ RECORD 1 ]--+-------------------------------
pid            | 550142
xact_age       | 00:00:06.867676
datname        | pgbench
relation       | pgbench_accounts
index          | -
state          | active
blocked_total  | 33
wait_event     | IO.DataFileExtend
phase          | seq scanning heap
size_total     | 257 MB
scanned,%      | 70.00
tuples_scanned | 1404122
tuples_written | 1404122
query          | VACUUM FULL pgbench_accounts;

В приведенном примере команда VACUUM FULL длится уже шесть секунд, она выполнена на 70 %, однако ее завершения ждут еще 33 сеанса, в которых выполняются запросы к перестраиваемой таблице. Соответственно, приложения, которые выполняют эти запросы, также заблокированы и вынуждены ждать завершения команды.

9.4. Представление pg_stat_progress_create_index

При активной разработке приложений и при появлении в приложении новых типов запросов создание индексов может быть довольно частой операцией. Создание индексов, особенно для больших таблиц, может занимать продолжительное время, требовать значительных ресурсов и влиять на производительность конкурентных запросов.

Для отслеживания используется представление pg_stat_progress_create_index, где каждая строка описывает отдельный процесс, в котором выполняется построение индекса:

  • pid — идентификатор процесса в операционной системе;

  • datid, datname — идентификатор и имя базы данных, в которой происходит операция;

  • relid — идентификатор таблицы, которой принадлежит индекс;

  • index_relid — идентификатор индекса, над которым выполняется операция;

  • command — выполняемая команда: CREATE INDEX, CREATE INDEX CONCURRENTLY, REINDEX или REINDEX CONCURRENTLY;

  • phase — фаза операции:

— initializing — подготовка к работе;

— waiting for writers before build — команды CREATE INDEX CONCURRENTLY или REINDEX CONCURRENTLY ожидают завершения транзакций, которые удерживают блокировки на запись и могут читать таблицу. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения фазы можно отслеживать в lockers_total, lockers_done и current_locker_pid;

— building index — методы доступа, поддерживающие отслеживание, передают статистику о своем состоянии. Детали построения индекса можно отслеживать в полях blocks_total и blocks_done, но также могут меняться и значения tuples_total и tuples_done;

— waiting for writers before validation — команды CREATE INDEX CONCURRENTLY или REINDEX CONCURRENTLY ожидают завершения транзакций, которые удерживают блокировки на запись и могут записывать в таблицу. Эта фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения фазы можно отслеживать в lockers_total, lockers_done и current_locker_pid;

— index validation: scanning index — команда CREATE INDEX CONCURRENTLY сканирует индекс на предмет строк, требующих проверки. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения фазы отражаются в полях blocks_total и blocks_done;

— index validation: sorting tuples — команда CREATE INDEX CONCURRENTLY сортирует строки, найденные в фазе сканирования;

— index validation: scanning table — команда CREATE INDEX CONCURRENTLY сканирует таблицу, чтобы проверить строки индекса, собранные в предыдущих двух фазах. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнение фазы отражаются в blocks_total и blocks_done; — waiting for old snapshots — команды CREATE INDEX CONCURRENTLY или REINDEX CONCURRENTLY ожидают освобождения снимков теми транзакциями, которые могут видеть содержимое таблицы. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения отражаются в lockers_total, lockers_done и current_locker_pid;

— waiting for readers before marking dead — перед тем как пометить старый индекс как нерабочий, команда REINDEX CONCURRENTLY ожидает завершения транзакций, удерживающих блокировки чтения. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения отражаются в lockers_total, lockers_done и current_locker_pid;

— waiting for readers before dropping — прежде чем удалить старый индекс, команда REINDEX CONCURRENTLY ожидает завершения транзакций, которые удерживают блокировки чтения. Фаза пропускается при выполнении операции в блокирующем режиме. Детали выполнения отражаются в lockers_total, lockers_done и current_locker_pid;

  • lockers_total — количество процессов, которых приходится ждать;

  • lockers_done — количество процессов, ожидание которых завершено;

  • current_locker_pid — идентификатор процесса, который удерживает блокировку в данный момент;

  • blocks_total (tuples_total) — общее количество блоков (строк), которое требуется обработать в данной фазе;

  • blocks_done (tuples_done) — общее количество блоков (строк), уже обработанных в данной фазе;

  • partitions_total — общее число секций, для которых должны быть созданы индексы (в случае работы с секционированной таблицей);

  • partitions_done — общее число секций, для которых уже выполнено создание индексов (в случае работы с секционированной таблицей).

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

Для получения результатов запроса в соседнем сеансе нужно запустить перестроение индекса:

# REINDEX CONCURRENTLY pgbench_accounts_pkey;

В сеансе с запросом к pg_stat_progress_create_index можно будет увидеть подобный вывод, из которого следует, что перестроение индекса находится в фазе сканирования таблицы, которая завершена на 75 %. После этого будет начата фаза загрузки строк, ход которой можно будет отследить в поле tuples_done,%.

# SELECT
    a.pid,
    now() - a.xact_start AS xact_age,
    p.datname,
    p.relid::regclass AS relation,
    p.index_relid::regclass AS index,
    a.state, a.wait_event_type ||'.'|| a.wait_event AS wait_event,
    p.phase,
    p.current_locker_pid AS locker_pid,
    p.lockers_total ||'/'|| p.lockers_done AS lockers,
    pg_size_pretty(p.blocks_total * (
        SELECT current_setting('block_size')::int)) AS size_total,
    round(100 * p.blocks_done /
        greatest(p.blocks_total, 1), 2) AS "size_done,%",
    p.tuples_total,
    round(100 * p.tuples_done /
        greatest(p.tuples_total, 1), 2) AS "tuples_done,%",
    p.partitions_total ||'/'|| round(100 * p.partitions_done /
        greatest(p.partitions_total, 1), 2) AS "parts_total/done,%",
    a.query
  FROM pg_stat_progress_create_index p
  INNER JOIN pg_stat_activity a ON p.pid = a.pid
  ORDER BY now() - a.xact_start DESC;
-[ RECORD 1 ]------+--------------------------------------------------
pid                | 550142
xact_age           | 00:00:02.523236
datname            | pgbench
relation           | pgbench_accounts
index              | pgbench_accounts_pkey
state              | active
wait_event         | LWLock.WALWrite
phase              | building index: scanning table
locker_pid         | 0
lockers            | 0/0
size_total         | 261 MB
size_done,%        | 75.00
tuples_total       | 0
tuples_done,%      | 0.00
parts_total/done,% | 0/0.00
query              | REINDEX INDEX CONCURRENTLY pgbench_accounts_pkey;

9.5. Представление pg_stat_progress_copy

Представление pg_stat_progress_copy используется для отслеживания команд COPY10, которые нужны для загрузки и выгрузки данных, в том числе и с помощью утилит pg_dump и pg_restore.

На больших объемах данных и при недостаточных ресурсах команда может выполняться продолжительное время и влиять на производительность конкурентных запросов.

Каждая строка в представлении описывает выполнение отдельной команды и содержит следующую информацию:

  • pid — идентификатор процесса в операционной системе;

  • datid, datname — идентификатор и имя базы данных, к которой выполнено подключение;

  • relid — идентификатор таблицы, с которой происходит работа;

  • command — выполняемая команда, COPY TO или COPY FROM;

  • type — метод ввод-вывода, который используется при работе с данными: FILE, PROGRAM, PIPE (для COPY FROM STDIN и COPY TO STDOUT) или CALLBACK в случае начальной синхронизации таблицы при логической репликации;

  • bytes_processed — общее число байтов, обработанных командой;

  • bytes_total — размер исходного файла в байтах в случае выполнения COPY FROM. Значение может быть равно нулю, когда размер определить нельзя;

  • tuples_processed — общее число строк, обработанных командой COPY;

  • tuples_excluded — общее количество строк, отброшенных указанным условием WHERE.

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

# SELECT
    a.pid,
    a.state, a.wait_event_type ||'.'|| a.wait_event AS wait_event,
    now() - a.xact_start AS xact_age,
    p.datname, p.relid::regclass AS relation,
    pg_size_pretty(pg_relation_size(p.relid)) AS table_size_total,
    c.reltuples::bigint AS table_tuples_total,
    p.tuples_processed,
    p.tuples_excluded,
    pg_size_pretty(p.bytes_total) AS source_file_total,
    pg_size_pretty(p.bytes_processed) AS processed,
    CASE WHEN p.command = 'COPY FROM'
      THEN round(100 * p.bytes_processed / greatest(p.bytes_total, 1), 2)
      ELSE round(100 * p.tuples_processed / greatest(c.reltuples::bigint, p.tuples_processed), 2)
    END AS "done,%",
    p.command || ' ' || p.type AS command,
    a.query
  FROM pg_stat_progress_copy p
  LEFT JOIN pg_class c ON p.relid = c.oid
  INNER JOIN pg_stat_activity a ON p.pid = a.pid
  ORDER BY now() - a.xact_start DESC;

Команда COPY имеет два режима работы — загрузка (COPY FROM) и выгрузка (COPY TO); в выводе для удобства режим объединен с указанием источника данных. Оценка выполненной работы (поле done,%) также учитывает оба режима.

Для оценки загрузки можно обойтись полями самого представления: bytes_total показывает размер исходного файла, из которого выполняется загрузка, а bytes_processed — количество байтов, прочитанных командой COPY. Следовательно, процент выполненной работы определяется отношением прочитанного объема к общему.

С оценкой выгрузки дело обстоит чуть сложнее: представление данных в СУБД отличается от формата выгрузки (не говоря уже о том, что и в СУБД данные могут по-разному сжиматься, и форматов выгрузки существует несколько), поэтому итоговый файл будет иметь совершенно другой размер, чем исходная таблица. В показанном запросе оценка вычисляется как отношение количества обработанных строк tuples_processed к общему количеству строк таблицы из поля pg_class.reltuples. Однако в этом способе тоже есть недостаток: pg_class.reltuples обновляется после очистки, и, если она выполнялась достаточно давно, значение не будет соответствовать действительности и оценка окажется неточной. Но опыт показывает, что такая оценка все равно получается более точной, чем оценка на основе bytes_processed и размера таблицы.

Запрос к pg_stat_progress_copy следует выполнить в одном сеансе с помощью метакоманды \watch 1, а в другом — запустить выполнение команды COPY или pg_dump:

# pg_dump -U postgres -t pgbench_accounts pgbench >/dev/null

В сеансе с запросом к pg_stat_progress_copy можно увидеть примерно следующее:

-[ RECORD 1 ]------+---------------------------------------------------------------------
pid                | 223457
state              | active
wait_event         | IO.DataFileWrite
xact_age           | 00:00:18.393571
datname            | pgbench
relation           | pgbench_accounts
table_size_total   | 277 MB
table_tuples_total | 1999223
tuples_processed   | 1755368
tuples_excluded    | 0
source_file_total  | 0 bytes
processed          | 169 MB
done,%             | 87.00
command            | COPY TO PIPE
query              | COPY public.pgbench_accounts (aid, bid, abalance, filler) TO stdout;

В приведенном примере таблица pgbench_accounts копируется командой COPY TO через конвейер на стандартный вывод (stdout). Выгрузка длится уже 18 секунд и завершена на 87 %. Кроме того, приведена дополнительная информация о состоянии процесса.

Резюме

  • СУБД располагает ограниченным набором представлений для отслеживания выполнения продолжительных команд.

  • Представления отслеживания хода выполнения не накапливают статистику и показывают текущее состояние процессов.

  • pg_stat_progress_vacuum используется для отслеживания операций очистки.

  • pg_stat_progress_analyze используется для отслеживания сбора статистики, необходимой планировщику.

  • pg_stat_progress_basebackup используется для отслеживания резервного копирования.

  • pg_stat_progress_cluster используется для отслеживания команд CLUSTER и VACUUM FULL.

  • pg_stat_progress_create_index используется для отслеживания команд CREATE INDEX и REINDEX.

  • pg_stat_progress_copy используется для отслеживания команд COPY.

  • Соединение представлений с pg_stat_activity и pg_locks повышает информативность.