PostgreSQL: JSONB vs JSON - скрытая причина деградации производительности, которую большинство проектов обнаруживает слишком поздно
Разница между json и jsonb в PostgreSQL выглядит незначительной только до момента, когда система начинает работать под реальной нагрузкой. На уровне синтаксиса оба типа делают одно и то же - хранят JSON. Но на уровне архитектуры базы данных они ведут себя принципиально по-разному.
И именно это различие становится причиной того, почему одни системы спокойно масштабируются, а другие начинают “тормозить без причины” после роста данных, даже если код и запросы не менялись.
Что PostgreSQL делает с JSON на самом деле
Когда используется json, база хранит данные как обычный текст. PostgreSQL не понимает структуру заранее и каждый раз при обращении к полям вынужден заново разбирать JSON-строку. Фактически это означает, что структура данных существует только в момент выполнения запроса.
jsonb устроен иначе. При вставке PostgreSQL один раз парсит JSON, нормализует его, убирает лишние элементы и сохраняет уже готовую структуру в бинарном виде. После этого работа идёт не с текстом, а с предобработанным деревом данных, которое можно эффективно индексировать и использовать в запросах.
Это различие не видно в простых CRUD-операциях, но становится критическим, как только JSON начинает участвовать в фильтрации.
Где система начинает вести себя по-разному
На небольших таблицах оба типа выглядят одинаково. Но как только появляется запрос с фильтрацией по вложенному полю, поведение базы расходится.
SELECT *
FROM events
WHERE data->>'event' = 'click';При использовании json PostgreSQL вынужден проверять каждую строку, потому что у него нет оптимизированного способа доступа к структуре.
С jsonb появляется возможность использовать индекс и уйти от полного сканирования таблицы.
CREATE INDEX idx_events_event
ON events ((data->>'event'));На этом этапе разница перестаёт быть теоретической. Она напрямую влияет на время ответа API и нагрузку на CPU при росте данных.
Контринсайт, который ломает привычное понимание JSONB
Распространённое упрощение звучит так: jsonb быстрее json.
Но в реальности это утверждение неполное и часто вводит в заблуждение. jsonb ускоряет чтение и поиск, но увеличивает стоимость записи и обновления данных. В системах с высокой частотой записи, где данные редко читаются, эта разница может быть нейтральной или даже негативной.
Это означает, что выбор между json и jsonb - это не выбор “что быстрее”, а выбор между моделями нагрузки. jsonb оптимизирован под чтение и фильтрацию, а json - под минимально обработанное хранение без дополнительной стоимости на вставке.
Почему деградация всегда проявляется позже
JSON почти всегда появляется в проекте как временное решение. Он позволяет быстро запускать функциональность без проектирования схемы данных.
Проблемы начинаются позже, когда система растёт. Появляются фильтры, аналитика, отчёты, выборки по вложенным полям. В этот момент JSON перестаёт быть просто хранилищем и становится частью логики запросов.
Именно здесь возникает скрытая деградация: запросы начинают выполняться медленнее, нагрузка растёт, но причина не очевидна, потому что структура базы формально остаётся валидной.
Реальный сценарий, который повторяется в продакшене
В типичной системе событий пользователей данные сначала хранятся в json:
{"user_id": 42, "event": "click", "page": "/home"}На старте это удобно: нет миграций, нет схемы, высокая скорость разработки.
Но позже появляются запросы аналитики:
SELECT *
FROM events
WHERE data->>'event' = 'click';При росте таблицы до миллионов записей PostgreSQL начинает выполнять последовательное сканирование. Это не ошибка запроса - это ограничение выбранной модели хранения.
После перехода на jsonb и добавления индекса поведение системы меняется фундаментально: запросы начинают использовать индекс, и время выполнения перестаёт зависеть от размера таблицы.
ALTER TABLE events
ALTER COLUMN data TYPE JSONB USING data::jsonb;
CREATE INDEX idx_events_event
ON events ((data->>'event'));Когда JSON всё ещё уместен
json остаётся оправданным только в сценариях, где данные не участвуют в логике обработки. Это может быть хранение сырых webhook-запросов, архивирование внешних API-ответов или логирование, где важна полная сохранность исходного формата без трансформаций и без запросов по внутренним полям.
Как только появляется необходимость поиска, агрегации или индексации, JSON перестаёт быть эффективным инструментом и начинает ограничивать систему.
Архитектурная ошибка, которая встречается чаще всего
Самая частая проблема в реальных проектах заключается не в выборе между json и jsonb, а в попытке использовать JSON как замену нормализованной схемы базы данных.
Когда вся структура данных уходит в JSON-поля, система теряет предсказуемость, усложняется оптимизация запросов, ухудшается использование индексов и растёт стоимость сопровождения.
В таких архитектурах проблема производительности почти никогда не связана с PostgreSQL как системой. Она связана с тем, что база используется вне своей реляционной модели.
Почему JSONB стал стандартом в реальных backend-системах
В большинстве продакшн-систем основная нагрузка приходится не на запись, а на чтение и фильтрацию данных. Именно в этих сценариях jsonb даёт системное преимущество: он позволяет строить индексы, выполнять быстрые выборки и работать с вложенными структурами без полного обхода таблицы.
Дополнительная стоимость вставки компенсируется кратным выигрышем на чтении и масштабировании, особенно при росте данных.
Итог
Разница между json и jsonb - это не вопрос формата хранения и не синтаксическая деталь. Это выбор модели поведения данных внутри системы.
json подходит только для хранения информации без дальнейшей обработки. jsonb - это структурированный формат, рассчитанный на поиск, фильтрацию и масштабирование под нагрузкой.
Именно поэтому в реальных backend-системах выбор почти всегда смещается в сторону jsonb: не потому что он современнее, а потому что он соответствует тому, как данные реально используются в продакшене.
Комментарии
Чтобы оставить комментарий, войдите в аккаунт.