Всю профессиональную карьеру я так или иначе жил рядом с базами данных: начинал с Oracle, потом надолго перешёл на MS SQL Server и PostgreSQL (думаю, я здесь не один такой).

Обычно мы используем СУБД как инструмент: учитываем нюансы синтаксиса, оптимизатора, утилит и поведения движка — и решаем прикладные задачи. Но недавно, разворачивая очередной PostgreSQL‑кластер для продакшена, я поймал себя на мысли: не слишком ли много всего нужно поднять вокруг PostgreSQL, чтобы система работала одновременно безопасно и предсказуемо по производительности?

Это не пост “против PostgreSQL”. Скорее попытка разобраться, почему эксплуатация OLTP‑БД всё чаще превращается в конструктор — и что бы я ожидал от базы данных, если проектировать её сегодня, под реалии 2026 года.

Что изменилось за последние годы

Законы физики не поменялись: I/O всё ещё медленнее CPU и памяти. Но контекст вокруг баз данных изменился радикально:

  • Объёмы данных и число пользователей в продакшене выросли.

  • Железо стало другим: NVMe, большие объёмы RAM, другие профили задержек и параллелизма.

  • Среда эксплуатации стала другой: виртуализация, контейнеры, Kubernetes, immutable‑подходы, GitOps.

  • Поменялись модели использования: multi‑tenant SaaS (“одна БД на тысячи арендаторов”) или, наоборот — множество небольших инстансов.

  • Выросла планка безопасности и комплаенса: аудит, контроль ключей, минимизация доверенной базы (TCB), и threat model “ошибки и компрометации случаются”.

  • Появились языки и практики, которые повышают ожидания к качеству системного кода: Rust с идеей memory safety и Go как практичный язык для инфраструктурных систем. (Например, команда CockroachDB отдельно описывала, почему для их распределённой БД Go оказался удачным выбором: Why Go was the right choice for CockroachDB.)

Почему появляется “слой магии”

В таких условиях многие важные свойства продакшен‑системы получаются не из фундаментального контракта ядра, а из комбинации:

  • правильных настроек,

  • правильного операционного режима,

  • правильного набора расширений и инструментов,

  • правильного деплоя и практик команды.

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

Какие есть классы SQL‑БД (и почему я смотрю на OLTP)

Я попробовал оглядеться: может, проблема решена “рынком” и давно есть зрелые альтернативы, которые просто нужно начать использовать.

Если не брать в расчёт NoSQL (я сознательно говорю именно про транзакционный SQL‑слой), то в целом современные системы можно разделить на несколько классов:

  • Распределённые SQL (NewSQL): CockroachDB, YugabyteDB, TiDB.

  • Аналитические SQL (OLAP/MPP): ClickHouse, SingleStore.

  • Embedded / локальные SQL: SQLite, DuckDB.

  • Классические OLTP: и вот здесь, как ни странно, “полностью новых” игроков заметно меньше, чем ожидаешь.

И это возвращает меня к мысли: если менять фундамент зрелой OLTP‑СУБД сложно и рискованно, то интересно не только “что есть”, но и “какие свойства вообще должны быть у OLTP‑БД, если проектировать с нуля под текущую реальность”.

Типовые боли OLTP: PostgreSQL и MS SQL Server

Чтобы не опираться только на личный опыт, я собрал типовые проблемы, которые чаще всего всплывают в эксплуатации PostgreSQL и MS SQL Server (не как сравнение “кто хуже”, а как список классов сложностей, да тут еще можно было бы включить MySql и Oracle, но я себя пожалел ).

PostgreSQL (OLTP)

  • Autovacuum не успевает → bloat таблиц/индексов: из‑за MVCC “мёртвые” версии строк копятся, растёт размер таблиц, ухудшаются задержки (см. официально про вакуум и его роль в поддержании производительности и освобождении пространства: PostgreSQL docs — Routine Vacuuming).

  • Длинные транзакции / idle in transaction блокируют уборку: пока открытая транзакция держит старый snapshot, vacuum не может удалить версии строк, которые потенциально ещё видимы этой транзакции (хороший разбор практических симптомов и причин: Citus — Debugging Postgres autovacuum problems).

  • Wraparound pressure и freeze‑работы: вакуум (включая freeze) — обязательная часть жизненного цикла; при достижении порогов по “возрасту” транзакций может потребоваться тяжёлая фоновая работа (PostgreSQL docs — Routine Vacuuming).

  • Масштабирование по соединениям: PostgreSQL использует модель “process per connection” (каждое подключение обслуживается отдельным backend‑процессом), поэтому при большом числе клиентов почти неизбежно возникает потребность в пулере и дисциплине по соединениям (официально про установление соединений и роль postmaster: PostgreSQL docs — How Connections Are Established).

  • Память “умножается” под нагрузкой: при большом числе параллельных запросов легко получить неожиданный рост RSS, если не учитывать модель выделения памяти на операции (сортировки/хэши и т.п.).

MS SQL Server (OLTP)

  • Blocking и lock escalation: при накоплении большого числа locks возможна эскалация, что усиливает блокировки для конкурирующих транзакций (Microsoft описывает причины и подходы к диагностике/снижению: Resolve blocking problem caused by lock escalation).

  • Parameter sniffing → “то быстро, то медленно”: план кэшируется под один набор параметров, а на другом резко деградирует (частая причина нестабильной OLTP‑латентности).

  • Tempdb contention: активное использование temp tables/сортировок/версионирования может превратить tempdb в узкое место (особенно при неидеальной конфигурации).

  • Цена “покрывающих” индексов и широких INCLUDE: ускоряют чтения, но повышают стоимость DML и общий размер индексов.

  • План‑кэш и single-use ad‑hoc планы: при потоке уникальных запросов может раздуваться план‑кэш; у Microsoft есть отдельная рекомендация и настройка optimize for ad hoc workloads как раз для сценария с большим числом single‑use ad‑hoc batches: optimize for ad hoc workloads (server configuration option).

Общее для обеих (проявляется по‑разному)

  • Слишком много индексов: чтения быстрее, но записи резко дорожают; со временем индексный “долг” становится главным ограничением throughput.

  • Плохой дизайн транзакций: большие транзакции, удержание ресурсов дольше нужного, “чатти” доступ — усиливают и блокировки, и проблемы горизонта видимости MVCC.

  • Неподходящий паттерн соединений: тысячи коротких коннектов вместо пула почти всегда приводят к деградации (в PostgreSQL обычно острее из‑за process-per-connection модели) — см. модель соединений в доках PostgreSQL: How Connections Are Established.

Мой вывод: не “новая фича”, а новый контракт

Я для себя сформулировал мысль так:

Если OLTP‑БД в 2026 должна быть продакшен‑готовой, то ключевые свойства должны быть контрактом ядра, а не результатом тонкой настройки окружающей экосистемы.

Под “контрактом” я имею в виду гарантии вида:

  • “если включено X, это нельзя обойти молча”,

  • “фоновые процессы не могут бесконтрольно съесть latency‑бюджет”,

  • “если контекст безопасности не задан — запрос не выполняется”,

  • “аудит нельзя выключить так, чтобы никто не заметил”.

В следующей статье я продолжу эту линию: попробую собрать список требований к “OLTP‑БД с нуля в 2026”, а затем выбрать 1–2 пункта и разобрать их глубже (через реальные негативные сценарии и компромиссы, которые обычно скрыты за словом “просто включите настройку”).


Вопросы к сообществу (DBA / Ops)

Какие 3 вещи вы считаете “обязательными для продакшена” в OLTP‑БД в 2026 (без чего вы не подпишете запуск)?

  1. Что у вас болит сильнее: tail latency (p99/p99.9), обслуживание (vacuum/maintenance), или безопасность/комплаенс (аудит/ключи/изоляция)?

  2. Какие инциденты у вас повторяются чаще всего: bloat/vacuum, blocking/lock storms, спайки COMMIT, деградация планов, проблемы с соединениями?

  3. Какой минимальный набор обвязки вокруг PostgreSQL вы считаете обязательным (pooler, бэкапы, мониторинг, алерты, аудит, шифрование, политики доступа)?

  4. Где для вас проходит граница “это должна уметь БД” vs “это должна решать платформа вокруг” (оператор в K8s, service mesh, внешний KMS, внешние политики)?

  5. Нужен ли вам fail‑closed режим по умолчанию (нельзя забыть включить критичные меры), или важнее гибкость/совместимость?

Вопросы к сообществу (разработчики / архитекторы)

  1. В какой модели вы чаще живёте: один продукт — одна БД, или multi‑tenant SaaS (много арендаторов в одной БД/схеме/таблицах)?

  2. Что для вас важнее как для потребителя БД: “простая эксплуатация платформой” или “максимум возможностей в самой БД (фичи/расширяемость)”?

  3. PL/pgSQL / T‑SQL и вообще процедурный язык в БД: насколько он вам реально нужен сегодня? (Бизнес‑логика рядом с данными, триггеры, миграции, ETL, “тонкие” функции; или лучше всё держать в приложении и ограничиться SQL?)

  4. Если бы процедурный язык был опциональным модулем, какие требования вы бы к нему предъявили (безопасность, песочница, производительность, наблюдаемость)?

  5. Какие компромиссы вы готовы принять ради предсказуемого p99: меньше фич, меньше расширяемость, более строгие ограничения на запросы/транзакции?

Комментарии (15)


  1. Tzimie
    24.02.2026 13:24

    Статья хорошая но вопросы странные. Замочить от бизнеса. Например, в одной конторе процессинг real time и все помешаны на p95-p99 и latency в миллисекундах. В другой MSSQL более "бэкендный" уже после кафок всяких и там запросы уже с таймаутом 30 сек ок. А read-only реплика этого вообще для кубов и там запросы по часу.


    1. anishukserg Автор
      24.02.2026 13:24

      @Tzimie, спасибо — полностью согласен, что “обязательность” сильно зависит от профиля нагрузки и SLO: где-то считают миллисекунды на p99, а где-то 30с таймаут норм, и отдельная RO-реплика живёт своей жизнью.

      Моя цель этими вопросами как раз собрать разные “минимальные контракты продакшена” по классам (условно: latency‑critical OLTP / “обычный” backend OLTP / тяжёлые чтения и реплики) и понять, что люди считают ядром, а что — “обвязкой”. В продолжении, похоже, стоит явно разнести это по сценариям и задавать вопрос не “в целом”, а “для такого-то профиля”.

      Если не сложно: для вашего самого “болючего” сценария (процессинг/latency‑critical или наоборот) какие 3 вещи вы бы назвали самыми критичными?


      1. Tzimie
        24.02.2026 13:24

        Для real time critical это работа resource governor (он слишком сложен и при большом потоке коннекций начинает добавлять overhead), я бы ввел некешируешие операции (ленивый скан который не должен забирать себе кеш), стабильность планов (по real time переключение на другой план как минимум не надо делать днём под нагрузкой)


  1. Tzimie
    24.02.2026 13:24

    На самом деле MSSQL стоит своих денег (про особенности одной страны пока не говорим). Query store, resource governor, parameter sniffing... Ну в 2022 есть полипланы для разных параметров. Все из коробки. И люди кто работает с Постгрес как то странно смотрят когда их хотят навязать миграцию базы с MSSQL... Ну терабайт так 90...

    А что думаете вы, раз столкнулись и с тем и с другим? Я все хочу уйти на PostgresSQL но слишком много работы по MSSQL пока, нет времени. И слышал что много людей приходят в состояние шока. Как с машины пересел нас велосипед


    1. anishukserg Автор
      24.02.2026 13:24

      Да, SQL Server во многих местах реально выглядит как более “собранная машина” из коробки: Query Store, Resource Governor, много диагностики/управления планами, зрелые инструменты — и это экономит кучу времени и нервов, особенно на больших инсталляциях.

      И это, кстати, прямо ложится в мой тезис про “конструктор”: в Postgres похожие свойства часто достигаются комбинацией ядра + расширений + внешних компонентов + практик эксплуатации. Работает, но требует дисциплины и “обвязки” — и на миграции это ощущается особенно остро.

      Про “терабайт 90”: я бы не воспринимал переход как “просто захотели — переехали”. На таком объёме миграция обычно оправдана только при очень конкретной бизнес‑причине (стоимость лицензий/вендор‑лок, требования к платформе/деплою, унификация стека, дефицит MSSQL‑экспертизы и т.п.). На практике чаще заходят не big‑bang, а с новых сервисов/контуров, постепенно наращивая долю Postgres — и вместе с долей растёт и экспертиза, как управлять им на таком объёме.

      Про “велосипед после машины”: соглашусь, но шок у людей обычно не от SQL как языка, а от разных “продакшен‑дефолтов” (соединения/пуллинг, vacuum и bloat, наблюдаемость/diagnostics, политики ресурсов).

      При этом если запускаешь новый проект и продакшином ещё не пахнет, мне часто проще и приятнее поднять Postgres, чем поднимать SQL Server.


  1. anishukserg Автор
    24.02.2026 13:24

    Да


  1. VVitaly
    24.02.2026 13:24

    OLTP нагрузка конечно бывает "разной", но если это "реальный" OLTP профиль он должен "по универсальности" приближаться к Oracle. К примеру (без "перекручивания" десятка параметров) оптимально поддерживать R/W нагрузку и как 1/9 и 3/7. Кэшировать данные один раз на множество сессий, не выделять один "тяжелый объект" в системных "словарях" БД на 10000 пользовательских сессий и т.п.
    Дисковый IO давно уже не главный "тормоз" OLTP нагрузки. Oracle "тормозит" только на блокировках (важна частота/латенси памяти и CPU), а в PG эти блокировки и тормоза "умножаются" за счет vacuum и analyze. Сбор статистики это конечно не плохо, но произвольное/автоматическое изменение планов исполнения "на лету" - попытка упростить "тупым" разработчикам/администраторам работу с БД.


    1. anishukserg Автор
      24.02.2026 13:24

      Спасибо — тут во многом согласен, и как раз это хороший “приземляющий” контекст к моему тезису.

      • Про “реальный OLTP” и универсальность уровня Oracle: да, если говорить про один инстанс, много сессий, R/W, предсказуемый tail, то ожидания часто именно такие: общие кэши/словари “один раз на всех”, минимальный per-session overhead, без сюрпризов на 10k сессий. И это не вопрос “фич”, это вопрос архитектурных инвариантов (память, конкуренция, контроль фоновой работы).

      • Про дисковый I/O vs CPU/память/локи: согласен, в современных OLTP-профилях bottleneck часто уезжает в конкуренцию и координацию (locks/latches, cacheline contention, latency памяти). И да — в PostgreSQL vacuum/analyze добавляют ещё один измеритель “конкуренции вокруг жизненного цикла данных/статистики”, который оператору приходится держать в голове.

      • Про auto-изменение планов “на лету”: я бы сформулировал мягче. Сбор статистики сам по себе полезен, но проблема начинается там, где для продакшена нет явных рамок стабильности: “вот так система может менять поведение, вот так — не может”, и это наблюдаемо и управляемо. Не потому что разработчики “тупые”, а потому что цена регрессии плана в OLTP — это p99 для бизнеса.

      Если интересно, уточню вопрос: вы больше за модель “план должен быть стабилен, а изменения — только через явные действия (pin/force/approve)”, или за модель “автоматика ок, но должна быть ограничена guardrails + быстрый откат”?


      1. Tzimie
        24.02.2026 13:24

        В терминах MSSQL я бы предложил оставить все как есть по умолчанию но в процедуры добавил бы WITH REALTIME чтобы менять поведение


  1. akod67
    24.02.2026 13:24

    Не думаю, что о базах, любых, стоит вот так говорить в отрыве от общей архитектуры системы. Думаю все уже достаточно за последние десятилетия походили по граблям, что бы воспринимать базу данных в контексте "должна вытянуть любые нагрузки". Нет, не должна. Большинство нагрузок должны быть подхвачены слоями выше (кеширование, поддерживаемые рид онли сэты данных в KV и прочее).


    1. anishukserg Автор
      24.02.2026 13:24

      Согласен. База почти никогда не существует “в вакууме”, и попытка требовать “вытяни любые нагрузки” — это прямой путь к разочарованию и неправильным ожиданиям.

      Я бы только добавил нюанс, который для меня и является ключевым:

      • Да, слои выше (cache, KV, read models, CQRS-подобные схемы) обязаны брать часть нагрузки.

      • Но ядро БД всё равно должно иметь контракт поведения под стрессом: когда кеш промахнулся, когда случился всплеск соединений, когда фоновые процессы догоняют хвост, когда multi-tenant “шумит”. Если в эти моменты БД деградирует хаотично, то “слои выше” часто лишь маскируют проблему до первого большого промаха.

      То есть я за позицию: архитектура системы задаёт профиль нагрузки, а контракт БД задаёт предсказуемое поведение внутри этого профиля (и честный отказ/ограничение за его пределами).

      Если вы согласны, то вопрос: какие “слои выше” вы считаете обязательными по умолчанию для OLTP в 2026 (кеш, queue, read-only projections, rate limiting), а какие — строго “по ситуации”?


      1. akod67
        24.02.2026 13:24

        Опять же, вряд ли стоит рассуждать в отрыве от задачи. Есть задачи, где нагрузка не может быть взрывной по определению, так же и нет непредсказуемой деградации схемы (тупо продукт относительно стационарен во времени по пользовательской базе, росту функционала и т.п.). Там и нет смысла городить огороды, по крайней мере в первых версиях.

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


        1. anishukserg Автор
          24.02.2026 13:24

          Да, это прям в точку, согласен.

          Если продукт и нагрузка по природе стационарные (нет взрывного роста, функционал/схема меняются редко, пользовательская база предсказуема), то действительно нет смысла с v1 городить “платформу на стероидах”. В таких задачах зачастую выигрывает простота и минимальная операционная поверхность.

          А вот когда есть риск “взрывов” и мульти-акторности, я бы тоже начал с двух базовых вещей:

          1) Кэширование с контролируемым прогревом

          Чтобы не устраивать stampede на БД при рестартах/релизах/инвалидациях, и чтобы прогрев был наблюдаемым и дозированным.

          2) Контролируемая очередь на запись в “жирные” таблицы

          Фактически — admission control/backpressure на write‑путь: лучше заранее и управляемо ограничивать скорость записи (и иметь понятную деградацию), чем ловить хаотичные блокировки/очереди ожиданий уже внутри БД.

          Если уточнить: под “очередью на запись” вы имеете в виду в приложении/шине (Kafka/Redis/DB-backed queue), или именно внутри слоя БД (типа write-admission + bounded queue per table/tenant)?


          1. akod67
            24.02.2026 13:24

            С LLM какой версии я веду переписку? =)


            1. anishukserg Автор
              24.02.2026 13:24

              Я ждал этого вопроса :)