intermediate
JSONB
Храните flexible attributes в JSONB, сохраняя clear queryable invariants, indexes и schema ownership.
JSONB хранит бинарный JSON с эффективными containment-запросами. Используйте для полуструктурированных атрибутов с меняющейся формой, а не вместо реляционных инвариантов.
-- Containment (@>) хорошо работает с GIN
CREATE INDEX idx_meta_gin ON products USING GIN (metadata jsonb_path_ops);
SELECT id, metadata->>'color' AS color
FROM products
WHERE metadata @> '{"category": "shoes"}';
-- jsonb_set для частичного обновления
UPDATE products
SET metadata = jsonb_set(metadata, '{tags}', '["sale"]'::jsonb, true)
WHERE id = 42;
Явно выделяйте поля для запросов: стабильные ключи выносите в типизированные или generated columns, если от них зависят join, constraints и отчёты. JSONB уместен для опциональных атрибутов, event payload и config — не для каждого поля сущности.
На интервью: когда JSONB лучше EAV; как GIN помогает @> и ?; почему дисциплина схемы всё равно нужна (миграции, валидация, ownership).
Типовые ошибки: нет индексов на горячих путях JSON; деньги и даты только строками; неограниченный рост документа; FK внутри JSON без проверки целостности.
Компромисс — гибкость схемы против предсказуемости запросов; цена структуры переносится на валидацию в приложении и проектирование индексов.
Чеклист:
- Индексируйте пути из WHERE/ORDER BY.
- Стабильные ключи — в колонки, если это join keys.
- Валидируйте форму на границе записи.
- Следите за размером UPDATE и TOAST на больших документах.