core code helper

PostgreSQL 18: що нового і чи варто оновлюватись

Асинхронний ввід-вивід, uuidv7(), віртуальні згенеровані колонки, OLD/NEW у RETURNING і інші зміни 18-ї версії — що з цього дасть користь вашому проєкту і на що звернути увагу при оновленні.

0 імпортували Імпортувати собі

PostgreSQL 18 вийшов восени 2025 року і за рік отримав кілька мінорних оновлень — тобто вже достатньо «відлежався» для продакшену. Розберемо зміни, які найпомітніші в щоденній роботі, і нюанси оновлення.

Асинхронний ввід-вивід

Найбільша зміна під капотом. Раніше PostgreSQL читав дані з диска синхронно: запросив сторінку — чекає. Тепер з'явилась підсистема асинхронного I/O, яка дозволяє видати кілька запитів на читання одночасно і не чекати кожен окремо.

SHOW io_method;      -- worker (за замовчуванням) або io_uring на Linux
  • worker — асинхронність через окремі процеси, працює всюди;
  • io_uring — нативний механізм ядра Linux, потребує збірки з підтримкою liburing.

У першій версії асинхронно виконуються читання: послідовні скани, bitmap heap scan, VACUUM. Найбільший виграш — на мережевих дисках у хмарі з високою латентністю. Навантаження з великою кількістю дрібних записів (типовий OLTP) кардинально швидшим не стане.

Порада

Новий системний вид pg_aios показує операції вводу-виводу, які виконуються зараз, — корисно для діагностики.

uuidv7()

SELECT uuidv7();
-- 0199a5f2-4c1b-7e3a-9d41-6f2b8c0e1a77

UUID версії 7 починається з мітки часу, тож нові значення впорядковані за часом. Для первинних ключів це важливо: випадкові UUIDv4 вставляються в довільні місця B-tree індексу, викликаючи розщеплення сторінок і погіршуючи кешування. UUIDv7 поводиться майже як автоінкремент — нові ключі йдуть у кінець індексу.

CREATE TABLE events (
  id   uuid PRIMARY KEY DEFAULT uuidv7(),
  kind text NOT NULL,
  data jsonb
);
Примітка

Мітка часу в UUIDv7 видна всім, хто бачить ідентифікатор. Якщо час створення об'єкта — чутлива інформація, для публічних ID краще залишити UUIDv4.

Віртуальні згенеровані колонки

Згенеровані колонки тепер можуть бути віртуальними — обчислюватись при читанні, без зберігання на диску. І саме VIRTUAL став поведінкою за замовчуванням.

CREATE TABLE products (
  name      text          NOT NULL,
  price_net numeric(10,2) NOT NULL,
  vat_rate  numeric(4,2)  NOT NULL DEFAULT 0.20,
  -- обчислюється при читанні (VIRTUAL за замовчуванням)
  price_gross numeric(10,2) GENERATED ALWAYS AS (price_net * (1 + vat_rate)),
  -- зберігається на диску: потрібна для індексу
  search_tsv  tsvector GENERATED ALWAYS AS (to_tsvector('simple', name)) STORED
);
Увага

Якщо ваші міграції створюють згенеровані колонки без явного STORED, у PostgreSQL 18 вони стануть віртуальними. Віртуальну колонку не можна проіндексувати — для індексів і повнотекстового пошуку пишіть STORED явно.

OLD і NEW у RETURNING

Тепер у RETURNING можна отримати і старі, і нові значення — без тригерів і додаткових запитів:

UPDATE accounts SET balance = balance - 100
WHERE id = 42
RETURNING old.balance AS before, new.balance AS after;

Зручно для аудиту, логування змін і логіки «повернути, що змінилось».

Темпоральні обмеження

Первинні й унікальні ключі з WITHOUT OVERLAPS забороняють перетин періодів — наприклад, щоб одна кімната не була заброньована двічі на той самий час:

CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE bookings (
  room_id int,
  during  tstzrange,
  PRIMARY KEY (room_id, during WITHOUT OVERLAPS)
);

Безпека і доступ

  • OAuth 2.0 як метод автентифікації — інтеграція з корпоративними провайдерами ідентичності;
  • автентифікація MD5 оголошена застарілою — переходьте на SCRAM-SHA-256, якщо ще не перейшли.
-- Знайти користувачів, у яких пароль досі зберігається як MD5
SELECT rolname FROM pg_authid WHERE rolpassword LIKE 'md5%';

Оновлення стало менш болісним

pg_upgrade тепер переносить статистику планувальника. Раніше після мажорного оновлення база кілька годин працювала на «порожній» статистиці, доки не відпрацював ANALYZE, і запити могли отримувати погані плани. Також з'явилась опція --swap, яка пришвидшує оновлення великих кластерів.

Чекліст оновлення

  1. Перевірити сумісність розширень (PostGIS, pgvector, TimescaleDB тощо) з 18-ю версією.
  2. Знайти в міграціях згенеровані колонки без явного STORED.
  3. Перевести паролі з MD5 на SCRAM.
  4. Прогнати тести застосунку на копії бази з PostgreSQL 18.
  5. Зробити свіжий бекап, перевірити відновлення, потім pg_upgrade --link або логічну реплікацію для мінімального простою.
  6. Після оновлення стежити за планами найважчих запитів — pg_stat_statements в допомогу.
Чому uuidv7 кращий за gen_random_uuid() для первинного ключа великої таблиці?

UUIDv7 впорядкований за часом, тому нові ключі додаються в кінець B-tree індексу, як автоінкремент. Випадкові UUIDv4 розкидаються по всьому індексу, викликаючи розщеплення сторінок, більший розмір індексу і гірше використання кешу.

Збережіть статтю собі

Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.

Увійти через Google Інші способи входу