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]
- RADIUS-аутентификация удалена. PostgreSQL поддерживал только RADIUS поверх UDP, который невозможно обезопасить, поэтому его убрали. Если
pg_hba.confссылается на RADIUS - этот путь сломается; вместо него нужен LDAP, OAuth или встроенные методы.[2] standard_conforming_stringsтеперь всегдаon. Это больше не настройка. Критично: дампы, сделанные пре-19pg_dump/pg_dumpallс этой настройкой off, не загрузятся в 19 корректно. При дампе старого кластера для восстановления используйтеpg_dumpиз 19 (или поставьтеstandard_conforming_strings = on), иначе получите тонкие ошибки со строковыми литералами.[2]- Индексы на
inet/cidrпод новым углом. Дефолтный opclass этих типов меняется сbtree_gistна GiST, потому чтоbtree_gist-opclass для inet/cidr сломан - он может исключать строки, которые должен возвращать. Поэтомуpg_upgradeзапретит апгрейд любого кластера, где естьbtree_gist-индекс поinetилиcidr. Если это ваш случай - дропайте или перестраивайте такие индексы до апгрейда, иначе жёсткий стоп.[2] - Дефолт
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_gistinet/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, который наконец говорит правду.
Источники
- 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 - 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 - 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
- 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 - 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