JSON у реляційній базі доречний, коли дані:
- мають змінну або заздалегідь невідому структуру: налаштування, метадані інтеграцій, атрибути товарів різних категорій;
- читаються й пишуться цілком, разом із рядком;
- рідко беруть участь у фільтрах, з'єднаннях і агрегатах.
Окрема таблиця краща, коли:
- за полями потрібно фільтрувати, сортувати, групувати, з'єднувати;
- потрібні обмеження:
NOT NULL, унікальність, зовнішні ключі; - елементи масиву - самостійні сутності, які змінюють поштучно (коментарі, позиції замовлення).
PostgreSQL: json чи jsonb. jsonb зберігається в розібраному бінарному вигляді: трохи повільніший запис, зате швидкі оператори (->, ->>, @>, ?) і підтримка GIN-індексів. json зберігає текст як є (з пробілами й порядком ключів) і майже ніколи не потрібен.
CREATE INDEX products_attrs_gin ON products USING gin (attributes);
SELECT * FROM products WHERE attributes @> '{"color": "red"}';
MySQL: тип JSON з валідацією; для індексу за полем створюють згенеровану колонку (GENERATED ALWAYS AS (attributes->>'$.color')) або функціональний індекс (8.0.13+).
Червоні прапорці: JSON-колонку, з якої постійно витягують одне поле в WHERE, часто варто перетворити на звичайну колонку. А зберігання в JSON списку ID інших записів - це втрачений зовнішній ключ.