PostgreSQL 19 уже почти вышел, и для тех, кто держит свою базу на VPS, это редкий major-релиз, к которому стоит присмотреться до выхода, а не после. Четвёртая бета вышла 24 сентября 2026,[1] первый кандидат в релизы (RC 1) - 15 октября 2026. Второй кандидат выйдет вместе с плановым update-релизом 12 ноября, а GA запланирован на 19 ноября 2026.[5] Это ваше время на подготовку, в течение которого лучше сделать апгрейд скучным, а не страшным.

Этот гайд держится только на том, что реально есть в текущих release notes 19, честно отмечает две заглавные фичи, которые убрали на этапе беты (планировать под отменённую фичу - верный способ сломать апгрейд), и даёт конкретный план pg_upgrade с 18, который вы запустите в момент выхода GA.

До планирования: две фичи откатили на бете

Release notes, с которыми вы встретитесь на GA, - это не то же самое, что маркетинг ранних бет 19. Два заголовочных пункта исчезли на Beta 4:[1][2]

  • Property-graph query (SQL/PGQ) - фича, позволявшая обходить граф SQL-подобным синтаксисом, была откачена на Beta 4, а не перенесена в point-релиз. В текущих release notes 19 её нет.[1][2]
  • Temporal tables через FOR PORTION OF - временные update/delete по SQL:2011 тоже откатили на Beta 4.[1][2]

PostgreSQL намеренно консервативен: если фича не дотягивает до качества к GA, её режут, а не выпускают полуготовой. Практический вывод для вашего плана прост - не стройте новую логику приложений под фичу бета-периода. Если вы видели слайд или ветку на HN, обещавшие PGQ в проде, - для 19 этого не будет. Стройте под release notes в том виде, в котором они есть на момент GA.

Что реально нового в 19 и что вы почувствуете на VPS

Ниже - изменения, сверенные с release notes 19 по состоянию на 1 октября 2026 года, отобранные под то, что важно, когда вы self-hostите одну машину или небольшой кластер.[2]

REPACK заменяет VACUUM FULL и CLUSTER

Раздувание диска - классическая проблема self-hosted PostgreSQL: вы удаляете строки, таблица остаётся толстой, и рано или поздно VACUUM FULL появляется в ваших пятничных планах. PostgreSQL 19 вводит REPACK, объединяющий VACUUM FULL и CLUSTER в одну команду - старые сохранены для совместимости, но учить стоит именно REPACK.[2]

Главный выигрыш - опция CONCURRENTLY: REPACK ... CONCURRENTLY перестраивает таблицу без access-exclusive lock, так что чтения и записи продолжают идти, пока идёт repack.[2] На продовом VPS, где таблицу, которую нужно уплотнить, нельзя снимать в 2 часа ночи, это разница между окном обслуживания и не-событием.

REPACK (CONCURRENTLY) orders;

Есть и ограничения, которые стоит знать. Конкурентный repack работает через replication slots, и в 19 добавлена GUC max_repack_replication_slots, управляющая их числом.[2] Если у вас открыто много репликационных слотов, заложите запас при переносе настроек.

Parallel autovacuum

Autovacuum - фоновый процесс, который не даёт таблицам умереть, и в 19 он наконец умеет распараллеливать вакуумирование индексов таблицы.[2] Максимум задаётся серверной переменной autovacuum_max_parallel_workers и потабличным параметром autovacuum_parallel_workers.[2]

Здесь есть и второй, тихий, но важный апдейт: 19 добавляет scoring-систему, которая решает, какие таблицы autovacuum обрабатывает в первую очередь, когда он отстаёт. Управляется она набором переменных autovacuum_*_score_weight и видна потаблично в новом представлении pg_stat_autovacuum_scores.[2] На нагруженном VPS с сотнями таблиц это важнее чистого параллелизма - очередь вакуума больше не застревает из-за одной огромной редко используемой таблицы.

ON CONFLICT DO SELECT ... RETURNING

Upsert, который не может сказать, что он сделал, - теперь в прошлом. В 19 у INSERT ... ON CONFLICT появляется форма DO SELECT ... RETURNING, возвращающая конфликтующую строку (и опционально блокирующая её через FOR UPDATE/FOR SHARE).[2] Если вы писали логику «сначала прочитай, потом вставь» с гонками, или таблицу-очередь, где «вставь, если нет, иначе отдай строку» постоянно спотыкается о конкурентных писателей, - это закрывает реальный пробел.

JIT теперь выключен по умолчанию - прочитайте дважды

Это главный пункт миграции, на котором большинство споткнётся. PostgreSQL 19 отключает JIT по умолчанию - раньше он был включён и срабатывал по оценке стоимости запроса, которую разработчики признали ненадёжной.[2]

Для OLTP-базы на VPS JIT off почти всегда небольшой плюс (меньше накладных на компиляцию каждого запроса). Но если вы гоняете много тяжёлых аналитических запросов - всё, что по оценкам планировщика раньше запускало JIT, - после апгрейда его придётся включить явно, иначе аналитика может замедлиться. Настройка - одна строка, но она помогает только если вы о ней знаете:

# postgresql.conf (только если вы полагаетесь на JIT для аналитики)
jit = on

Сайтам с серьёзной аналитикой в 19 JIT нужно включать вручную - больше он не включится сам.[2]

Breaking-изменения, которые стоит проверить до запуска

Раздел «Migration to Version 19» в release notes перечисляет несовместимости. Вот четыре, которые чаще всего задевают self-hosted-установку:[2]

  1. RADIUS-аутентификация удалена. PostgreSQL поддерживал только RADIUS поверх UDP, который невозможно обезопасить, поэтому его убрали. Если pg_hba.conf ссылается на RADIUS - этот путь сломается; вместо него нужен LDAP, OAuth или встроенные методы.[2]
  2. standard_conforming_strings теперь всегда on. Это больше не настройка. Критично: дампы, сделанные пре-19 pg_dump/pg_dumpall с этой настройкой off, не загрузятся в 19 корректно. При дампе старого кластера для восстановления используйте pg_dump из 19 (или поставьте standard_conforming_strings = on), иначе получите тонкие ошибки со строковыми литералами.[2]
  3. Индексы на inet/cidr под новым углом. Дефолтный opclass этих типов меняется с btree_gist на GiST, потому что btree_gist-opclass для inet/cidr сломан - он может исключать строки, которые должен возвращать. Поэтому pg_upgrade запретит апгрейд любого кластера, где есть btree_gist-индекс по inet или cidr. Если это ваш случай - дропайте или перестраивайте такие индексы до апгрейда, иначе жёсткий стоп.[2]
  4. Дефолт max_locks_per_transaction удваивается с 64 до 128, и изменилось выделение памяти под locks - то есть существующие настройки locks теперь придётся примерно удвоить для той же ёмкости. Также в именах БД/ролей/табличных пространств запрещены переводы строки и carriage return (и pg_upgrade откажет кластеру, который их использует), а кодировка MULE_INTERNAL удалена (пострадавшим базам нужен dump/restore в другой кодировке).[2]

Два из них - блокировщик btree_gist inet/cidr и правило дампа для standard_conforming_strings - стоит греть прямо сегодня, потому что чинить их лучше до недели GA, а не во время неё.

План апгрейда: 18 → 19

Major-апгрейды никогда не бывают in-place. В документации 19 перечислены три поддерживаемых пути - pg_dumpall, pg_upgrade или logical replication.[3] Для VPS почти всегда правильный выбор - pg_upgrade в режиме --link: апгрейд занимает минуты вместо дампа и восстановления всего датасета, и downtime минимален.[3]

Вот последовательность, которую я бы прогнал, когда выйдет GA. Резервную копию не пропускать.

1. Предварительные проверки

# текущая версия и расположение данных
postgres --version
psql -c 'SHOW data_directory;'

# найти btree_gist inet/cidr индексы ДО апгрейда (pg_upgrade их не пропустит)
psql -d mydb -c "
SELECT c.relname AS index_name, i.indrelid::regclass AS table_name, opc.opcname
FROM pg_index i
JOIN pg_class c ON c.oid = i.indexrelid
JOIN pg_opclass opc ON opc.oid = ANY(i.indclass::oid[])
WHERE opc.opcname IN ('gist_inet_ops', 'gist_cidr_ops');
"

Opclass-ы btree_gist для inet/cidr называются gist_inet_ops и gist_cidr_ops (штатный GiST-класс ядра - inet_ops), поэтому запрос выводит ровно те индексы, которые pg_upgrade откажется переносить.[2][4] Прогоните его в каждой базе кластера. Пересоздайте такие индексы со штатным opclass inet_ops (или удалите их) до начала миграции - обычный REINDEX сохраняет старый opclass и не поможет.

2. Настоящий бэкап

pg_upgrade --link быстрый, потому что делает hard-link на файлы данных - а значит мутирует ваш data directory. До запуска нужна восстановимая копия:

pg_dumpall > /backup/pre19_$(date +%F).sql

Используйте бэкап как страховку, а не как основной механизм миграции. Полный дамп/восстановление через pg_dumpall - второй поддерживаемый путь, если хотите медленно и просто, и это проверенный временем дефолт, когда pg_upgrade упирается в крайний случай.[3]

3. Ставим бинарники 19, останавливаем старый сервер

Установите PostgreSQL 19 из репозитория вашего дистрибутива (переключением версий занимаются скрипты пакетного менеджера - в их документации смотрите хелперы для major-апгрейда). Затем остановите работающий сервер 18:

sudo systemctl stop postgresql@18-main   # юнит уточняется по дистрибутиву

4. Запускаем pg_upgrade

С обоими наборами бинарников запускаем новый pg_upgrade. Флаг --link и делает его быстрым:

# от пользователя postgres; пути зависят от дистрибутива
sudo -u postgres /usr/lib/postgresql/19/bin/pg_upgrade \
  --old-bindir /usr/lib/postgresql/18/bin \
  --new-bindir /usr/lib/postgresql/19/bin \
  --old-datadir /var/lib/postgresql/18/main \
  --new-datadir /var/lib/postgresql/19/main \
  --link --check        # dry-run

Сначала прогоните с --check - это dry-run, который только проверяет совместимость и ничего не меняет, - почините всё, что он укажет (как минимум btree_gist inet/cidr индексы), затем запустите ту же команду без --check по-настоящему. Полная процедура pg_upgrade, включая выполняемые им проверки, описана в руководстве по апгрейду.[3]

5. Проверка и «оживление» (systemd хочет restart)

После апгрейда документированный systemd-пример в 19 теперь включает настройку restart - её стоит скопировать в свой юнит, чтобы сервис корректно переживал рестарты демона.[2] Затем:

sudo systemctl start postgresql@19-main
sudo -u postgres psql -c 'SELECT version();'   # должно быть 19.x

Пользователям logical replication: в 19 реплицируются значения последовательностей, и логическую репликацию можно включать без перезапуска сервера при wal_level = replica - это важно, если вы прогоняете роллинг-миграцию без жёсткого cutover.[2]

Что сделать, пока есть время

Честный вывод: разрушительная часть перехода 18→19 - это удаления и дефолты, а не новые фичи. У вас есть месяц или больше, чтобы снять риски. Конкретно:

  • Найдите и перестройте btree_gist inet/cidr индексы сейчас - иначе pg_upgrade откажет всему кластеру, а эта подготовка не требует даунтайма, если строить замену конкурентно.
  • Спланируйте тест дампа 19-версией pg_dump, если апгрейдите через restore, чтобы поведение standard_conforming_strings было проверено до cutover.
  • Решите вопрос JIT по реальной нагрузке - на миграции включите его в postgresql.conf, если у вас много аналитики.
  • Проверьте pg_hba.conf на RADIUS и подготовьте замену метода аутентификации.
  • Протестируйте на черновом кластере - поднимите 19 параллельно, залейте копию, прогоните ваш read-path. Документация по апгрейду прямо рекомендует тестировать клиентские приложения против новой версии до переключения.[3]

Если пропустить планирование и просто запустить pg_upgrade в четверг GA, самый вероятный отказ - жёсткий стоп на btree_gist inet/cidr, ровно потому, что это наименее заметная несовместимость. Прогрейте её сейчас - и остальная часть релиза почти чистый плюс: REPACK без блокировок, autovacuum, который перестаёт будить вас в три часа ночи, и upsert, который наконец говорит правду.

Источники

  1. PostgreSQL Global Development Group - «PostgreSQL 19 Beta 4 Released!» (Beta 4, 2026-09-24; RC на начало октября, GA может последовать в том же месяце; перечислены откаченные на Beta 4 фичи, включая SQL/PGQ и FOR PORTION OF). https://www.postgresql.org/about/news/postgresql-19-beta-4-released-3386/ - проверено 2026-10-01
  2. PostgreSQL 19 Documentation - «E.1. Release 19» release notes (REPACK, parallel autovacuum, ON CONFLICT DO SELECT ... RETURNING, JIT off по умолчанию, удаление RADIUS, standard_conforming_strings принудительно on, блокировка btree_gist inet/cidr в pg_upgrade, дефолт max_locks_per_transaction, удаление MULE_INTERNAL, systemd restart; по состоянию на 2026-09-14). https://www.postgresql.org/docs/19/release-19.html - проверено 2026-10-01
  3. PostgreSQL 19 Documentation - «18.6. Upgrading a PostgreSQL Cluster» (методы upgrade: pg_upgrade / pg_dumpall / logical replication; тестирование клиентских приложений на новой версии). https://www.postgresql.org/docs/19/upgrading.html - проверено 2026-10-01
  4. PostgreSQL 19 Documentation - «F.8. btree_gist» (§F.8.2: gist_inet_ops / gist_cidr_ops ненадёжны; в 19 дефолтом для inet/cidr стал штатный inet_ops). https://www.postgresql.org/docs/19/btree-gist.html - проверено 2026-10-03
  5. PostgreSQL Global Development Group - «PostgreSQL 19 RC 1 Released!» (2026-10-15; RC 2 - в день update-релиза 2026-11-12; GA запланирован на 2026-11-19). https://www.postgresql.org/about/news/postgresql-19-rc-1-released-3409/ - проверено 2026-10-17