Команда Go for Devs подготовила перевод обзора PostgreSQL 18. Новый релиз не ограничился громкой подсистемой асинхронного ввода-вывода — он принёс ряд функций, заметных именно в повседневной разработке. Нативная поддержка UUID v7, виртуальные генерируемые столбцы, расширенные возможности RETURNING
и новые средства диагностики делают жизнь разработчиков проще и продуктивнее.
PostgreSQL 18 официально вышел 25 сентября 2025 года. Несомненно, самым значимым изменением стала новая подсистема асинхронного ввода-вывода (AIO). Однако в этой статье основное внимание уделено функциям, которые повлияют на повседневную работу разработчиков, начиная с нативной поддержки UUID v7.
Нативная поддержка UUID v7
Коммит: 78c5e141e
Документация: https://www.postgresql.org/docs/18/datatype-uuid.html
PostgreSQL 18 представляет функцию uuidv7()
для генерации значений UUID версии 7. Эта нативная поддержка практически завершает давние споры о том, использовать ли типы SERIAL/IDENTITY или UUID в качестве первичных ключей. UUIDv7 объединяет лучшее из обоих миров: глобальную уникальность UUID с последовательной природой, что обеспечивает высокую производительность serial ключей.
-- Сгенерировать UUIDv7
SELECT uuidv7();
-- Создать таблицу, используя UUIDv7 в качестве первичного ключа
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT uuidv7(),
customer_id INT,
total DECIMAL(10,2),
created_at TIMESTAMP DEFAULT NOW()
);
Хотя расширения для PostgreSQL могли генерировать UUIDv7, наиболее широко используемое расширение uuid-ossp не реализует седьмую версию UUID. Менее известные расширения, которые поддерживают v7, обычно не поставляются с дистрибутивами PostgreSQL, особенно у облачных провайдеров. Это означало, что разработчикам, желающим использовать UUIDv7, приходилось реализовывать логику генерации в своих приложениях. Нативная поддержка полностью устраняет это препятствие.
Виртуальные генерируемые столбцы
Коммит: 83ea6c540
Документация: https://www.postgresql.org/docs/18/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-STORED
Генерируемые столбцы впервые появились в PostgreSQL 12, но только с параметром STORED, что означало, что сгенерированный столбец хранится при записи и занимает место на диске. Добавление генерируемого столбца STORED приводило к перезаписи всей таблицы.
PostgreSQL 18 представляет параметр VIRTUAL и делает его поведением по умолчанию для генерируемых столбцов. Эти столбцы вычисляют свои значения при чтении, а не при записи. Это более распространенный подход, и то, что он стал по умолчанию, приводит PostgreSQL в соответствие с другими основными базами данных.
-- Create table with virtual generated column
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
salary DECIMAL(10,2),
-- You can also skip VIRTUAL since it's the default option
annual_salary DECIMAL(12,2) GENERATED ALWAYS AS (salary * 12) VIRTUAL
);
-- Insert data (generated columns are computed automatically)
INSERT INTO employees (first_name, last_name, salary) VALUES
('John', 'Doe', 5000.00),
('Jane', 'Smith', 6500.00);
SELECT first_name, last_name, salary, annual_salary
FROM employees;
Преимущества виртуальных столбцов:
Экономия места: для производных данных, которым не требуется физическое хранение, виртуальные столбцы исключают избыточное использование диска.
Динамические вычисления: некоторые вычисления выгодно выполнять во время выполнения запроса, особенно когда они зависят от текущего состояния системы.
С другой стороны, генерируемые столбцы типа STORED
остаются ценными для сложных вычислений, которые редко меняются, когда затраты на производительность при многократных вычислениях перевешивают соображения хранения.
Однако существуют определённые ограничения, как указано в коммите. Наиболее заметное из них заключается в том, что нельзя создавать индексы на генерируемых столбцах типа VIRTUAL
.
Кстати, PostgreSQL 18 также добавляет поддержку генерируемых столбцов в логической репликации (коммит, документация). Эта функция доступна только для генерируемых столбцов типа STORED
.
Старые и новые значения в RETURNING
Коммит: 80feb727c
Документация: https://www.postgresql.org/docs/current/dml-returning.html
PostgreSQL 18 улучшает выражение RETURNING
, позволяя получать доступ как к старым, так и к новым значениям строк в DML-операциях. Это устраняет необходимость в отдельных запросах для захвата значений до/после в журналах аудита.
Операции UPDATE
-- Обновить цены и увидеть как старые, так и новые значения
UPDATE products
SET price = price * 1.10
WHERE price <= 99.99
RETURNING
name,
old.price AS old_price,
new.price AS new_price,
new.price - old.price AS price_change;
Операция INSERT с ON CONFLICT
-- Upsert с отслеживанием изменений
INSERT INTO products (name, price) VALUES ('Widget', 25.00)
ON CONFLICT (name) DO UPDATE SET price = EXCLUDED.price
RETURNING
name,
old.price AS previous_price,
new.price AS current_price,
(old.price IS NULL) AS is_new_record;
Операции DELETE
-- Отслеживать, что было удалено
DELETE FROM products
WHERE price < 10.00
RETURNING
old.name AS deleted_product,
old.price AS deleted_price;
EXPLAIN ANALYZE с BUFFERS по умолчанию
Коммит: c2a4078eb
Документация: https://www.postgresql.org/docs/current/sql-explain.html
PostgreSQL 18 улучшает команду EXPLAIN для автоматического предоставления более подробной информации о выполнении запросов.
Теперь EXPLAIN ANALYZE
по умолчанию включает информацию об использовании буферов, что устраняет необходимость в параметре BUFFERS
. Такое поведение по умолчанию помогает разработчикам выявлять проблемы с производительностью ввода-вывода, которые в противном случае остались бы незамеченными:
postgres=# EXPLAIN ANALYZE SELECT * FROM users WHERE age > 25;
-- PostgreSQL 18: BUFFERS включены автоматически
Seq Scan on users (cost=0.00..18.75 rows=125 width=64) (actual time=0.029..0.087 rows=178 loops=1)
Filter: (age > 25)
Rows Removed by Filter: 89
Buffers: shared hit=12
Planning:
Buffers: shared hit=156 read=3
I/O Timings: shared read=0.024
Planning Time: 0.512 ms
Execution Time: 0.734 ms
pg_get_acl() для проверки привилегий
Коммит: 4564f1ceb
Документация: https://www.postgresql.org/docs/18/functions-info.html#FUNCTIONS-INFO-OBJECT-TABLE
PostgreSQL 18 представляет функцию pg_get_acl()
для программного получения списков контроля доступа (ACL) для объектов базы данных. Если вы когда-либо тратили время на отладку печально известных сообщений ERROR 42501: permission denied
, вы оцените наличие унифицированного способа проверки привилегий объектов.
Ранее для устранения проблем с разрешениями требовалось запрашивать различные системные каталоги (pg_class
, pg_proc
, pg_namespace
, pg_attribute
) в зависимости от типа объекта, каждый из которых имел свой формат ACL.
Функция pg_get_acl()
предоставляет унифицированный интерфейс для получения ACL из любого объекта базы данных, устраняя необходимость запоминать, какой каталог запрашивать для разных типов объектов.
postgres=# SELECT
(pg_identify_object(s.classid,s.objid,s.objsubid)).*,
pg_catalog.pg_get_acl(s.classid,s.objid,s.objsubid) AS acl
FROM pg_catalog.pg_shdepend AS s
JOIN pg_catalog.pg_database AS d
ON d.datname = current_database() AND
d.oid = s.dbid
JOIN pg_catalog.pg_authid AS a
ON a.oid = s.refobjid AND
s.refclassid = 'pg_authid'::regclass
WHERE s.deptype = 'a';
-[ RECORD 1 ]-----------------------------------------
type | table
schema | public
name | testtab
identity | public.testtab
acl | {postgres=arwdDxtm/postgres,foo=r/postgres}
Хотя эти улучшения не так сенсационны, как новый AIO, они упрощают повседневную разработку — а более понятные интерфейсы, такие как pg_get_acl()
, приносят пользу не только разработчикам-людям, но и ИИ-агентам.
Русскоязычное Go сообщество

Друзья! Эту статью подготовила команда «Go for Devs» — сообщества, где мы делимся практическими кейсами, инструментами для разработчиков и свежими новостями из мира Go. Подписывайтесь, чтобы быть в курсе и ничего не упустить!
VladimirFarshatov
А вот про асинхронный ввод-вывод, почитал бы тоже с удовольствием, особенно режим записи при вставке данных в табличку, да ещё и с имеющимися индексами.