ESPN DeportesEl Porto, con Gimenez en la banca, se mide ante el sotaneroESPNHow a group of Texas students, alumni turned overnight stadium camp-outs into traditionThe Jerusalem PostSaudi pipeline attack exposes growing power of Iran-backed militias - analysisRTP DesportoLando Norris conquista pole para Grande Prémio de Espanha por 11 milésimosPunch2027: Haske dumps APC, picks Adamawa APM gov ticketוואלהגבר בן 23 נפל מסוס סמוך לתל שבע - מצבו בינוניWirtualna PolskaZastąpił Morawieckiego. Bielan nowym szefem EKRThe South AfricanWeather: Cloudy skies set to bring showers and rainDeadline‘ER’s Big Payday: How Hit Medical Drama Scored Record $13M An Episode From NBC – Book ExcerptOnet88-letnia pacjentka wypadła z okna szpitala w Koninie. Nie przeżyła upadkuANSALa benzina vola, rebus nuovi sostegni per il governo
The Daily Newsstand · Free, Always
Saturday, September 12, 2026

PostgreSQL умер, да здравствует… PostgreSQL?

Translate

Привет, Хабр. Я хочу рассказать историю, которую вы уже, наверняка, где-то слышали. Только с другой стороны.

Пару месяцев назад я сидела на созвоне с техдиром стартапа, который делал RAG-систему для юридических документов. Он сказал, что они уходят с Postgres на Pinecone, потому что Postgres для векторов не тянет, это же очевидно. Я спросила, сколько у них векторов. Оказалось, тысяч двести, может, триста. Я уточнила, пробовали ли они вообще pgvector. Выяснилось, что нет, решение приняли по общему ощущению, что Postgres для этого не годится. Ощущение было не на пустом месте, два года назад так и было. Я не стала спорить. Просто открыла документацию pgvector и скинула ссылку. Через неделю он написал, что оно работает. Даже быстрее, чем они думали. Ещё через месяц они запустили прод. На одном Postgres. Без Pinecone. Без отдельной векторной базы. Без трёх месяцев инфраструктурной работы, которую они уже успели запланировать.

И это не единичный случай. Мне кажется, что это паттерн. И я хочу разобрать его по частям, потому что за последние пару лет я видела этот сценарий минимум пять раз в разных вариациях, и каждый раз он заканчивался одинаково.

Смерть первая, официальная

PostgreSQL уже умирал. Официально. В 1994 году.

Проект POSTGRES, рождённый в Беркли под руководством Майкла Стоунбрейкера, был закрыт на версии 4.2. Причина не в том, что технология провалилась, наоборот, она оказалась слишком успешной. К 1993-му пользователи приходили, задавали вопросы, требовали багфиксы, и это съедало всё время исследователей. Стоунбрейкер хотел писать следующую научную работу, а не заниматься бесплатной техподдержкой. В академическом мире это нормально, проект живёт, пока приносит статьи. Как только он начинает приносить тикеты, его закрывают. Версию 4.2 выпустили в 1994-м, в основном чтобы прибраться за собой, и на этом всё.

Была и вторая проблема, посерьёзнее. POSTGRES говорил на собственном диалекте PostQUEL. Красивом в научных статьях, но бесполезном в реальном мире, который уже проголосовал за SQL. База данных, которая не понимает стандартный язык запросов, обречена на академическое забвение. Тогда это было очевидно всем, кроме, пожалуй, самих авторов.

Проект умер. Официально. Строкой в документации. Представьте себе, не заморожен, не передан сообществу.

А потом случилось то, что не попало в учебники. Двое студентов, Andrew Yu и Jolly Chen, взяли мёртвый код и сделали две вещи. Первая, написали SQL-интерпретатор на bison и flex, чтобы база заговорила на языке, который понимает мир. Вторая, вычистили код до полностью ANSI C, сократив его на четверть. В документации это формулируется как completely ANSI C, trimmed by 25%. Звучит как строчка из код-ревью, а на самом деле это описание того, как из академического артефакта сделали работающий продукт.

В 1995 году появилась Postgres95. На обложке руководства два имени. Через год оба ушли из проекта. Дальше были Marc Fournier, Bruce Momjian, Tom Lane и десятки других, кто строил сообщество. Но именно те два студента сделали невозможное. Они переписали проект на языке будущего.

Урок номер один. PostgreSQL умирает не тогда, когда его объявляют мёртвым, а когда перестаёт говорить на языке современности. В 94-м это был SQL. В 2026-м это SQL плюс векторы плюс JSONB плюс всё остальное, что придумают завтра.

Смерть вторая, векторы

Сегодня PostgreSQL снова хоронят. На этот раз из-за AI.

Логика простая и на первый взгляд безупречная. У вас есть эмбеддинги, у вас есть RAG, у вас есть семантический поиск. Для этого нужна векторная база данных. Pinecone, Weaviate, Qdrant. А Postgres вообще реляционная база, она не для этого. Точка.

Я сама через это прошла. В 2024-м мы строили рекомендательную систему для маркетплейса. Векторов было около восьми миллионов, размерность 768. Первая мысль, ну конечно, отдельная векторная база. Собрали прототип на Qdrant. Работало. Красиво. Latency в районе десяти миллисекунд на простых запросах, документация приятная, клиент на Python одно удовольствие. Мы уже начали рисовать архитектурную схему для презентации инвесторам.

Но потом начались вопросы, от которых хотелось выть.

Где хранить метаданные товаров? В Postgres. Где хранить историю взаимодействий? В Postgres. Где хранить пользователей и их предпочтения? Тоже в Postgres. Где хранить фичи для ранжирования, которые мы пересчитываем каждую ночь? Угадайте. И вот у нас три базы, между которыми нужно синхронизировать данные. Транзакций нет. Консистентности нет. При деплое нужно думать о порядке запуска сервисов, о миграциях в трёх системах, о том, что если векторная база упадёт, то вся выдача сломается. А если упадёт Postgres, сломается вообще всё.

Мы потратили месяц на инфраструктуру. Месяц, который не принёс ни одной новой фичи. Месяц, за который мы могли бы запустить A/B-тест, собрать метрики, понять, что вообще работает.

Тогда я сделала то, что делают упрямые инженеры. Поставила pgvector и перенесла всё в один Postgres.

Как это выглядит в коде

Вот тот самый гибридный поиск в двадцать строк, которым я хвасталась коллегам. Сначала схема.

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE products (
    id          bigserial PRIMARY KEY,
    title       text NOT NULL,
    description text,
    price_cents int,
    in_stock    boolean DEFAULT true,
    embedding   vector(768),
    search_tsv  tsvector GENERATED ALWAYS AS (
        to_tsvector('russian',
            coalesce(title, '') || ' ' || coalesce(description, ''))
    ) STORED
);

CREATE INDEX ON products USING hnsw (embedding vector_cosine_ops)
    WITH (m = 16, ef_construction = 64);

CREATE INDEX ON products USING gin (search_tsv);

Обратите внимание на search_tsv. Это генерируемая колонка, Postgres сам пересчитывает её при каждом апдейте строки. Никакого триггера, никакой отдельной джобы, никаких мыслей про то, а вдруг индекс отстал от данных.

Дальше сам запрос. Смешиваем два ранжирования через Reciprocal Rank Fusion, то есть берём позицию документа в каждой выдаче, а не сырые скоры. Косинусное расстояние и ts_rank_cd живут в разных вселенных, складывать их напрямую бессмысленно.

SET hnsw.ef_search = 100;

WITH semantic AS (
    SELECT id, row_number() OVER (ORDER BY embedding <=> $1) AS rank
    FROM products
    WHERE in_stock
    ORDER BY embedding <=> $1
    LIMIT 50
),
lexical AS (
    SELECT id, row_number() OVER (ORDER BY ts_rank_cd(search_tsv, q) DESC) AS rank
    FROM products, plainto_tsquery('russian', $2) AS q
    WHERE in_stock AND search_tsv @@ q
    ORDER BY ts_rank_cd(search_tsv, q) DESC
    LIMIT 50
)
SELECT p.id, p.title, p.price_cents
FROM semantic s
FULL OUTER JOIN lexical l USING (id)
JOIN products p USING (id)
ORDER BY coalesce(1.0 / (60 + s.rank), 0)
       + coalesce(1.0 / (60 + l.rank), 0) DESC
LIMIT 20;

Немного строк, и это вместо сервиса, который надо было бы писать, тестировать и поддерживать.

Пара оговорок, чтобы вы не наступили на наши грабли.

Первая. ts_rank_cd никакой не BM25. Встроенный полнотекстовый поиск Postgres считает релевантность по-своему, и если вам нужен именно BM25, с честной нормализацией по длине документа и насыщением по частоте терма, то придётся ставить расширение вроде pg_search от ParadeDB или VectorChord-bm25. Нам хватило ts_rank_cd, но я видела задачи, где разница в метриках оказывалась заметной.

Вторая. Условие WHERE in_stock рядом с HNSW-индексом, это та самая ловушка, из-за которой люди и уходят в специализированные базы. ANN-индекс возвращает вам ближайших соседей, а потом фильтр их выкашивает, и в выдаче остаётся десять строк вместо пятидесяти. В pgvector 0.8 появились итеративные сканы (hnsw.iterative_scan), которые добирают кандидатов, пока не наберётся нужное количество. Стало сильно лучше. Но если у вас фильтр отсекает 99% таблицы, проверяйте recall руками, планировщик вам об этом не скажет.

Где проходит граница

Восемь миллионов векторов по 768 измерений, это около 25 гигабайт сырых данных, плюс HNSW-граф, плюс сама таблица с метаданными. В сумме у нас получилось порядка пятидесяти гигабайт, и мы держали их на инстансе, где всё это влезало в память с запасом.

Вот это, собственно, и есть граница. Момент, когда HNSW-индекс перестаёт помещаться в RAM. Пока помещается, вы получаете десятки миллисекунд. Как только начинается чтение с диска на каждом обходе графа, латентность уезжает на порядок, и никакие настройки ef_search вас не спасут. Второй звоночек, это время сборки индекса. На нашем объёме полный CREATE INDEX занимал часы, и это надо закладывать в планы, а не узнавать в ночь перед релизом.

Поэтому, когда вас спрашивают, потянет ли Postgres, правильным ответом будет простая арифметика. Количество умножить на размерность, умножить на 4 байта, умножить примерно на два на граф, и сравнить с объёмом памяти инстанса. Для 1536-мерных эмбеддингов от OpenAI получится вчетверо хуже, чем у нас. А если перейти на halfvec, то вдвое лучше, pgvector умеет хранить половинную точность, и на большинстве задач recall от этого страдает незначительно.

Так что фраза про то, что Postgres не тянет векторы, правдива только за определённым порогом. И порог этот считается в гигабайтах.

Но вот что важно. Большинство проектов до этого порога никогда не дойдут. Они будут жить в зоне, где Postgres объективно лучше. Потому что ACID-транзакции поверх векторов и метаданных, это отсутствие целого класса багов, которые вы бы отлаживали в распределённой системе. Это возможность сделать INSERT в таблицу товаров и таблицу эмбеддингов в одной транзакции. Это возможность откатить всё, если что-то пошло не так. Это возможность не думать о том, что векторная база отстала на пять минут от реляционной.

Когда всё-таки не Postgres

Здесь я должна остановиться. Иначе получится агитка, а я не за этим пришла.

Есть сценарии, где pgvector плохой выбор, и никакая любовь к одной базе этого не изменит.

Когда индекс не влезает в память. Про это выше. Если у вас сто миллионов эмбеддингов по 1536 измерений, вы либо покупаете инстанс с чудовищным объёмом RAM, либо идёте в систему, которая изначально спроектирована под диск и шардирование. Postgres умеет партиционировать таблицы, но у него нет встроенного шардирования векторного индекса по нодам. Это придётся строить руками поверх, и вот тут выделенная база выигрывает.

Когда векторная нагрузка конкурирует с OLTP. Поиск по HNSW выедает page cache. На том же инстансе, где у вас идут обычные транзакции. Можно вынести на реплику, можно разнести по tablespace, но вы всё равно решаете задачу, которой в раздельной архитектуре просто нет.

Когда нужна тонкая настройка ретривала. Квантование, multi-vector, переранжирование внутри движка, отдельные политики для разных коллекций. Qdrant и Weaviate дают ручки, которых в pgvector нет и, скорее всего, не будет. Если вы всерьёз занимаетесь качеством поиска, а не тем, чтобы просто работало, вам эти ручки понадобятся.

Когда индекс надо перестраивать часто. Если эмбеддинги переезжают на новую модель раз в месяц, многочасовая пересборка становится операционной проблемой, а не разовым неудобством.

Если хотя бы два пункта из этих четырёх про вас, не читайте дальше, идите смотреть на специализированные базы. Я серьёзно.

Смерть третья, версии

Пока я писала эту статью, наткнулась на очередное напоминание о датах. PostgreSQL 14 достигнет end of life 12 ноября 2026 года. И тут же в комментариях на Хабре, на Reddit, в тг каналах начинается привычное нытьё про то, что опять миграции, опять сломанные расширения, опять всё горит.

Но апгрейд минорной версии не смерть. PostgreSQL развивается, и end of life предыдущей версии это не похороны. Тем более что экосистема расширений давно перестала быть набором плагинов и стала полноценной платформой. Сегодня вы можете поднять Postgres с TimescaleDB для time-series, PostGIS для геоданных, pg_search для полнотекстового поиска и pgvector для эмбеддингов, и всё это будет работать в одной транзакции. Попробуйте сделать то же самое с четырьмя разными базами.

И да, обновляться стоит. В PostgreSQL 18 появился асинхронный I/O, а для нагрузок вроде векторного поиска, где чтения идут вразнобой по всему индексу, это заметная разница. Сам pgvector при этом живёт своей жизнью. Актуальная версия 0.8.6 от 29 июля 2026-го, и её стоит поставить хотя бы ради 0.8.2, где закрыли переполнение буфера при параллельной сборке HNSW-индексов (CVE-2026-3172). Кстати, если вы читаете это и у вас в проде pgvector старше 0.8.2, сходите обновитесь, а потом возвращайтесь.

Смерть четвёртая, которой не будет

Есть ещё один сценарий, о котором говорят реже. Якобы Postgres умрёт от того, что станет слишком сложной. Слишком много расширений, слишком много настроек, слишком много способов сделать одно и то же. Новичок приходит, видит shared_buffers, work_mem, effective_cache_size, wal_level, max_wal_size, и уходит в ужасе. Может, лучше взять что-то простое?

Я слышала этот аргумент десятки раз. И каждый раз он разбивается об одно и то же. Сложность Postgres можно осваивать порциями.

Только давайте начистоту. Совет оставить дефолты и ни о чём не думать плохой сам по себе. Дефолты у Postgres легендарно консервативные, shared_buffers из коробки 128 мегабайт, и на любой живой нагрузке это первое, что вы поменяете. Но обратите внимание, о чём речь. Это три-четыре параметра, которые гуглятся за вечер, а дальше можно годами ничего не трогать. Не нужно заранее разбираться в партиционировании, логической репликации, шардировании и векторном поиске. Postgres не требует, чтобы вы поняли всё сразу. Он позволяет начать с CREATE TABLE и SELECT и дойти до остального тогда, когда это действительно понадобится. А если не понадобится, вы ничего не потеряете.

Это, кстати, ключевое отличие от специализированных баз. Векторная база требует, чтобы вы сначала разобрались в векторах. Postgres позволяет разобраться в них потом. Или не разбираться вовсе.

Почему он не умрёт

У PostgreSQL есть свойство, которое я не встречала ни у одной другой технологии. Он умеет становиться тем, что нужно сейчас. В 90-х он стал SQL-базой. В 2000-х расширяемой. В 2010-х JSON-документным. В 2020-х векторным и AI-готовым.

Это архитектурное решение, принятое Стоунбрейкером в 1986 году, когда он заложил в POSTGRES поддержку абстрактных типов данных. Он тогда не мог знать, что через сорок лет это позволит добавить векторы, JSONB, PostGIS, TimescaleDB, pg_search и ещё сотню расширений, о которых никто не думал. Но механизм был. И он работает.

Сравните это с любой другой технологией. MongoDB стала документной базой и осталась ей. Redis стал key-value хранилищем и остался им. Они могут добавлять фичи, но они не могут сменить категорию. Postgres может. Именно поэтому его хоронят каждые пять лет, и именно поэтому он каждый раз выживает.

Векторные базы данных при этом никуда не денутся. В марте 2026-го Qdrant закрыл раунд B на 50 миллионов долларов под лидом AVP, после 28 миллионов серии A в начале 2024-го. На момент анонса у проекта было больше 250 миллионов скачиваний и около 29 тысяч звёзд на GitHub, а среди клиентов Tripadvisor, HubSpot и Bosch. Это компания, которая продаёт решение реальной проблемы реальным людям. Просто эта проблема не ваша, пока ваш индекс влезает в память.

Для всех остальных, у кого векторы живут рядом с заказами, пользователями, транзакциями и метаданными, Postgres уже здесь. И он работает.

Я не знаю, сколько человек прочтет эту статью. Но я знаю, что через пять лет кто-то снова напишет, что PostgreSQL умер. Потому что появится новая технология, новый хайп, новая категория, которая убьёт реляционные базы. Может быть, это будет что-то про графы, может быть, про knowledge graphs, может быть, про что-то, что мы пока не можем себе представить. И кто-то снова поставит pg_что-нибудь, и Postgres снова окажется достаточным.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.