PostgreSQL 18 принёс асинхронный I/O, UUID v7 и ещё кучу полезного. Но фича, которая нас реально радует — виртуальные вычисляемые колонки. Это способ держать бизнес-логику ближе к данным и не плодить триггеры и boilerplate-SQL.
Как было раньше: надо было дублировать одни и те же выражения в запросах, вьюхах, функциях. Забыл обновить — привет баги. С виртуальными колонками логика всегда в одном месте, и данные остаются консистентными.
Пример:
create table users (
id serial primary key,
name text not null,
-- stored: пишется на диск, индексируется
name_upper text
generated always as (upper(name)) stored,
-- virtual: считается на лету
name_lower text
generated always as (lower(name)) virtual
);
name_upper отлично индексировать, name_lower — не занимает места и моментально добавляется даже в огромную таблицу.А вот более практичный сценарий — полнотекстовый поиск на нескольких языках:
create table docs (
id serial primary key,
body text not null,
body_fts_simple tsvector
generated always as (to_tsvector('simple', body)) stored,
body_fts_en tsvector
generated always as (to_tsvector('english', body)) stored,
body_fts_el tsvector
generated always as (to_tsvector('greek', body)) stored
);
create index on docs using gin (body_fts_simple);
create index on docs using gin (body_fts_en);
create index on docs using gin (body_fts_el);
Теперь поиск по разным языкам не требует триггеров и всегда синхронизирован с данными.
Итого:
* virtual — для лёгких выражений, быстрых экспериментов и JSON-поля без дублирования.
* stored — для тяжёлых вычислений, которые нужны в индексах.
#postgres@go_for_devs