> Столкнулись ли вы с типами данных массивы и JSON в PostgreSQL (JavaScript, Go, PostgreSQL)

Уровень: senior · Роль: backend · Категория: Технические вопросы

Компании: Ютека

Стек: JavaScript, Go, PostgreSQL

> Пример ответа

Короткий ответ

Да, сталкивался. Массивы и JSON в PostgreSQL - это мощные инструменты, но их применение требует осознанного подхода. Массивы удобны для хранения однотипных скалярных значений, а JSON/JSONB - для полуструктурированных данных. Ключевой момент: JSONB позволяет индексировать и эффективно запрашивать вложенные структуры, но не заменяет нормализацию. Выбор между ними зависит от паттерна доступа: если нужны агрегации и join'ы - нормализованные таблицы, если гибкая схема и чтение целиком - JSONB.

Подробное объяснение

В PostgreSQL есть два отдельных семейства типов: массивы (integer[], text[], и так далее) и JSON (json, jsonb). Они решают разные задачи.

Массивы - это встроенный тип, который хранит список значений одного типа. Полезны, когда порядок важен и количество элементов ограничено. Примеры: теги, координаты, идентификаторы связанных сущностей. Но у массивов есть ограничения: нет встроенных индексов для поиска по элементу (нужен GIN с array_ops), и они неудобны для запросов с условиями на отдельные элементы.

JSONB - бинарное представление JSON. В отличие от json, он не сохраняет пробелы, порядок ключей и дубликаты, но зато поддерживает индексы (GIN, BTREE по выражению) и операторы @>, ?, ?|, ?&. JSONB позволяет хранить произвольную вложенность и менять структуру без миграций. Однако запросы к вложенным полям медленнее, чем к колонкам, и требуют аккуратного использования выражений.

Trade-off: если данные имеют фиксированную структуру и по ним строятся выборки с фильтрацией и join'ами - нормализованные таблицы. Если структура меняется часто, или данные приходят из внешнего API и используются целиком - JSONB. Массивы - компромисс для простых списков, когда не нужны сложные запросы.

На практике часто комбинируют: основные атрибуты - в колонках, а дополнительные, редко используемые - в JSONB. Это даёт гибкость без потери производительности на горячих путях.

На практике

В реальных проектах я использовал JSONB для хранения метаданных, настроек, ответов внешних сервисов, а также для реализации мягкой схемы (EAV-замена). Массивы - для хранения списков идентификаторов, когда не нужна связь через отдельную таблицу (например, список ID прикреплённых файлов).

Важный момент: при работе с JSONB в Go и JavaScript нужно помнить о сериализации. В Go - json.RawMessage или map[string]interface{}, в JavaScript - обычные объекты. Но при вставке через драйвер (например, pgx в Go) нужно передавать []byte или использовать json.Marshal.

Также стоит учитывать, что индексы на JSONB-полях работают не так, как на обычных колонках. GIN-индекс на data ускоряет @>, но не ускоряет data->>'field' = 'value' - для этого нужен BTREE-индекс на выражении.

Пример кода

SQL
-- Массивы
CREATE TABLE articles (
id serial PRIMARY KEY,
title text,
tags text[]
);
-- Поиск по элементу массива через GIN
CREATE INDEX idx_articles_tags ON articles USING GIN (tags);
SELECT * FROM articles WHERE tags @> ARRAY['postgres'];
-- JSONB
CREATE TABLE events (
id serial PRIMARY KEY,
payload jsonb
);
-- GIN-индекс для поиска по ключу
CREATE INDEX idx_events_payload ON events USING GIN (payload);
SELECT * FROM events WHERE payload @> '{"type": "click"}';
-- BTREE-индекс на конкретное поле
CREATE INDEX idx_events_user_id ON events ((payload->>'user_id'));
SELECT * FROM events WHERE payload->>'user_id' = '123';

Как отвечать на собеседовании

Начните с того, что оба типа использовали, но сразу разделите их назначение. Покажите понимание разницы между json и jsonb. Упомяните индексацию и производительность. Приведите конкретный пример из практики, где вы выбрали JSONB вместо нормализации, и объясните почему. Если спросят про альтернативы - скажите, что для строгой схемы лучше обычные таблицы, а JSONB - для гибких и редко запрашиваемых полей. Не углубляйтесь в синтаксис, если не просят - лучше показать понимание trade-off'ов.

Что проверяет интервьюер

Интервьюер оценивает:

  • понимание разницы между типами и их ограничениями;
  • умение обосновать выбор типа под задачу;
  • знание индексов и операторов для JSONB;
  • понимание влияния на производительность запросов;
  • способность объяснить, когда JSONB - это антипаттерн.

Типичные ошибки

  • Использование json вместо jsonb без причины - теряется производительность и индексация.
  • Хранение в JSONB данных, по которым нужны частые выборки и join'ы - это медленно и неудобно.
  • Создание GIN-индекса на всё JSONB-поле, когда запросы идут по конкретному ключу - нужен BTREE на выражении.
  • Игнорирование размера: JSONB хранит ключи в каждом документе, что увеличивает объём.
  • Попытка использовать массивы для сложных структур - лучше JSONB или отдельная таблица.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью