Команда REPACK CONCURRENTLY перестроила раздутую таблицу объёмом 355 МБ до 178 МБ в рабочей базе данных, при этом запрос INSERT поступил в середине перестройки и был зафиксирован без ожидания. Эта единственная команда устраняет последний повод для планирования простоев вокруг VACUUM FULL, и это лишь одно из нескольких изменений в PostgreSQL 19, которые влияют на повседневную работу, а не просто отражаются в списке изменений. второй бета-версии , выпущенной в середине июля, что позволяет ожидать общего выпуска (GA) в обычные сроки — в сентябре или октябре.
Каждое из приведённых ниже утверждений было проверено на лабораторном сервере, а не перефразировано из чернового варианта примечаний к выпуску. Проверенные функции: новая команда REPACK, параллельный autovacuum, переключение контрольных сумм данных в режиме онлайн, слияние и разделение партиций на месте, запросы к графу свойств, а также набор измененных значений по умолчанию, которые удивят любого, кто обновляет существующую установку PostgreSQL. Пакеты взяты из того же репозитория PGDG, который используется для установки PostgreSQL 19 в любых основных дистрибутивах.
Протестировано в июле 2026 года на PostgreSQL 19 Beta 2.
REPACK заменяет VACUUM FULL и CLUSTER
Проблема раздувания таблиц всегда имела два неудачных решения: VACUUM FULL, которое устанавливает блокировку ACCESS EXCLUSIVE и блокирует всё, либо внешнее pg_repack . В PostgreSQL 19 это исправление включено в ядро в качестве полноценной REPACK команды, а CONCURRENTLY перестраивает таблицу, пока продолжаются обычные операции чтения и записи. В приведённом ниже тестовом примере создаётся полмиллиона строк, а затем физический размер таблицы удваивается с помощью UPDATE по всей таблице:
CREATE TABLE bloated (id int PRIMARY KEY, data text);
INSERT INTO bloated SELECT g, repeat(md5(g::text), 10) FROM generate_series(1, 500000) g;
UPDATE bloated SET data = data || 'x';
SELECT pg_size_pretty(pg_relation_size('bloated'));
Неиспользуемые кортежи, оставшиеся после UPDATE, увеличивают размер кучи до 355 МБ. Одна команда освобождает это пространство без эксклюзивной блокировки:
REPACK (CONCURRENTLY) bloated;
SELECT pg_size_pretty(pg_relation_size('bloated')) AS after_repack;
Размер кучи возвращается ровно к половине своего раздутого значения:
after_repack
--------------
178 MB
Полная сессия, зафиксированная на тестовой машине:
Чтобы подтвердить заявление о параллелизме, а не просто поверить ему на слово, во второй сессии была вставлена строка через две секунды после начала выполняющегося repack. Команда INSERT завершилась немедленно, REPACK завершился после неё, и строка сохранилась после перегруппировки таблицы. Внутренне режим параллелизма использует логическое декодирование для воспроизведения изменений, внесённых во время копирования, поэтому существует новый max_repack_replication_slots параметр (по умолчанию 5). Примечательно, что весь тест проходил в стандартной конфигурации wal_level = replica, никаких изменений настроек не требовалось. Ход выполнения можно отслеживать в специальном pg_stat_progress_repack , наряду с существующими представлениями прогресса для vacuum и CLUSTER.
Команда plain REPACK без этого параметра ведет себя как VACUUM FULL (эксклюзивная блокировка, более быстрая перезапись), а REPACK ... USING INDEX выполняет то же, что и CLUSTER . Обе старые команды по-прежнему работают в версии 19, но именно REPACK будет получать новые функции в дальнейшем.
Параллельный autovacuum поставляется в отключенном состоянии
Autovacuum наконец-то может использовать параллельные рабочие процессы для вакуумирования индексов — тот же механизм, который VACUUM (PARALLEL n) имеет с версии 13. Но есть один нюанс: по умолчанию эта функция отключена. На свежем кластере Beta 2:
SHOW autovacuum_max_parallel_workers;
Значение по умолчанию — 0, что означает, что ни один рабочий процесс autovacuum не будет выполнять параллельную обработку, пока это значение не будет увеличено:
autovacuum_max_parallel_workers
---------------------------------
0
Включение этой функции осуществляется в два этапа. Общее ограничение на уровне сервера задается в autovacuum_max_parallel_workers (дополнительно ограничиваемое max_parallel_workers), а для каждой таблицы, которая должна получить от этого выгоду, требуется свой собственный параметр хранилища:
ALTER TABLE big_events SET (autovacuum_parallel_workers = 2);
Этот параметр отображается в pg_class.reloptions и оправдывает себя только для таблиц с несколькими крупными индексами — именно в этом и заключается слабое место autovacuum на загруженных системах сегодня. Определить, какие таблицы заслуживают этого, тоже стало проще: новый pg_stat_autovacuum_scores представляет оценки срочности для каждой таблицы, рассчитываемые запускающим модулем, включая давление переполнения, поэтому определение таблиц, с которыми autovacuum испытывает трудности, больше не сводится к догадкам. Этот вид хорошо сочетается с существующей конфигурацией мониторинга Prometheus и Grafana для отслеживания накопленного дефицита вакуумирования с течением времени.
Включение/отключение контрольных сумм данных в режиме онлайн
Начиная с версии 18, initdb по умолчанию включает контрольные суммы данных, но изменение этого параметра в существующем кластере требовало его отключения на pg_checksums. В PostgreSQL 19 добавлены две функции, которые позволяют включать или отключать контрольные суммы в работающем кластере:
SELECT pg_enable_data_checksums(cost_delay => 0, cost_limit => 100);
SELECT pg_disable_data_checksums();
Переход происходит асинхронно. Фоновый рабочий процесс перезаписывает каждую страницу и SHOW data_checksums сообщает о промежуточных состояниях во время работы. Снимок, сделанный в середине перехода на тестовом кластере:
data_checksums
----------------
inprogress-off
Через несколько секунд состояние установилось на окончательное значение. На кластере объёмом в несколько терабайт этот промежуток времени исчисляется часами, а не секундами, и для cost_delay существует аргумент, позволяющий ограничить скорость перезаписи, чтобы не перегрузить хранилище. Ход процесса можно отслеживать в новом pg_stat_progress_data_checksums . Для тех, кто несколько лет назад инициализировал кластер без контрольных сумм и с тех пор об этом сожалеет, это позволяет замкнуть цикл без необходимости выполнения дампа и восстановления или полного цикла резервного копирования и восстановления.
Объединение и разделение партиций на месте
MERGE PARTITIONS
Раньше переразбиение на партиции означало отсоединение, копирование и повторное присоединение вручную. Две новые ALTER TABLE операции позволяют выполнять это напрямую. Объединение двух разделов, охватывающих по полгода, в один:
ALTER TABLE metrics MERGE PARTITIONS (metrics_h1, metrics_h2) INTO metrics_2026;
SPLIT PARTITION
Обратная операция разбивает один раздел на несколько, при этом новые границы задаются непосредственно в команде:
ALTER TABLE metrics SPLIT PARTITION metrics_2026 INTO
(PARTITION metrics_q1 FOR VALUES FROM ('2026-01-01') TO ('2026-04-01'),
PARTITION metrics_q2 FOR VALUES FROM ('2026-04-01') TO ('2026-07-01'),
PARTITION metrics_h2b FOR VALUES FROM ('2026-07-01') TO ('2027-01-01'));
Обе операции без сбоев выполнились в Beta 2 и \d+ подтвердили итоговую структуру разбиений. Одно предупреждение для использования в производственной среде: во время выполнения эти операции устанавливают сильные блокировки на родительском объекте, поэтому их следует выполнять в окне обслуживания для активно используемых таблиц. Преимуществом является корректность и простота, а не параллелизм.
Запросы к графу свойств попадают в ядро SQL
PostgreSQL 19 реализует SQL/PGQ из стандарта SQL:2023. Граф свойств определяется как представление обычных таблиц, запросы к которому выполняются с использованием синтаксиса графовых шаблонов вместо рекурсивных соединений. Минимальная топология для двух таблиц:
CREATE PROPERTY GRAPH net_topo
VERTEX TABLES (hosts KEY (id) LABEL host PROPERTIES (name))
EDGE TABLES (links KEY (src, dst)
SOURCE KEY (src) REFERENCES hosts (id)
DESTINATION KEY (dst) REFERENCES hosts (id)
LABEL connects);
SELECT * FROM GRAPH_TABLE (net_topo
MATCH (a IS host)-[IS connects]->(b IS host)
COLUMNS (a.name AS from_host, b.name AS to_host));
Шаблон MATCH возвращает каждую ребро в виде строки:
from_host | to_host
-----------+---------
lb01 | web01
web01 | db01
Это не заменит специализированную графовую базу данных для глубокого обхода, но для цепочек зависимостей, сетевых путей и организационных схем, которые и так уже хранятся в реляционных таблицах, синтаксис шаблонов читается гораздо лучше, чем лестничная конструкция WITH RECURSIVE. Это следует той же траектории, что и pgvector для вложений: рабочие нагрузки, которые раньше оправдывали использование второй базы данных, продолжают сводиться к Postgres.
Небольшие изменения, заметные в повседневной работе
GROUP BY ALL группирует по каждому неагрегированному столбцу в целевом списке, что избавляет от утомительного повторения списков столбцов при проведении оперативной аналитики. INSERT ... ON CONFLICT DO SELECT finally возвращает существующую строку при конфликте вместо того, чтобы заставлять выполнять цикл «сначала ничего не делать, потом выбрать», и поддерживает FOR UPDATE для блокировки возвращаемого результата. Обе функции работали в Beta 2 точно так, как описано в документации:
SELECT region, product, sum(qty) FROM orders GROUP BY ALL;
INSERT INTO users (email) VALUES ('[email protected]')
ON CONFLICT (email) DO SELECT RETURNING id, email;
Утилитарный уровень включил функции генерации случайных чисел с учетом диапазона, такие как random('2026-01-01'::date, '2026-12-31'::date) для генерации тестовых данных, base64url и base32hex в encode()/decode(), прямые bytea в uuid преобразования, а также COPY ... TO ... (FORMAT json) для экспорта строк в формате JSON без цикла на стороне клиента. Логическая репликация получила синхронизацию последовательностей, поэтому при переключении на резервный сервер больше не используются устаревшие значения последовательностей, а представление по типу блокировки pg_stat_lock добавлено в каталог мониторинга.
Значения по умолчанию, которые меняются незаметно для вас
В версии 19 изменены несколько значений по умолчанию, которые обновления наследуют незаметно. Все они были проверены на стандартной установке Beta 2:
| Параметр | PostgreSQL 18 | PostgreSQL 19 |
|---|---|---|
default_toast_compression |
pglz | lz4 |
jit |
включено | выключено |
log_lock_waits |
выключено | включено |
max_locks_per_transaction |
64 | 128 |
| Аутентификация RADIUS | доступно | удалено |
Переключение JIT имеет наибольшее значение для аналитических рабочих нагрузок: все, что полагалось на JIT-компиляцию длительно выполняющихся запросов, после обновления незаметно теряет эту возможность и требует jit = on явно. Использование lz4 в TOAST по умолчанию — это явный плюс (более быстрое сжатие при аналогичных коэффициентах), но означает, что значения, недавно обработанные TOAST, больше не идентичны по байтам выводу pglz, что иногда имеет значение для дедупликации на уровне хранилища. А любая pg_hba.conf , в которой по-прежнему присутствует строка radius , не позволит серверу запуститься после обновления. Еще одна тонкость, касающаяся таблицы блокировок: в версии 19 изменился алгоритм выделения размера блокировок, поэтому удвоенное max_locks_per_transaction по умолчанию вмещает примерно столько же, сколько и раньше; тем, у кого установлено пользовательское значение, при обновлении следует удвоить его, а не просто скопировать.
Что следует протестировать перед выпуском GA
Бета-версия 2 не предназначена для производственной среды, а формат данных на диске может ещё измениться до выхода кандидатской версии, поэтому тестовые кластеры следует пересоздавать для каждой бета-версии, а не обновлять. Тесты, которые стоит провести сейчас на копии реальной рабочей нагрузки: REPACK CONCURRENTLY для самой раздутой таблицы (измерьте максимальный объем на диске во время перестроения, так как таблица на короткое время существует дважды), запуск с включенными контрольными суммами для измерения времени перезаписи в реалистичных условиях cost_delay, а также сравнение результатов EXPLAIN для десяти самых медленных запросов с отключенным JIT. Официальный выпуск (GA) обычно происходит в конце сентября или октябре; без проблем обновятся те команды, которые уже исчерпали все неожиданности на этапе бета-тестирования.