JSON и выбор правильного типа

Знакомимся с типом JSON в MySQL и собираем чек-лист, как выбирать тип данных для столбца.

JSON — тип столбца MySQL для хранения структурированных документов; база проверяет валидность JSON и умеет извлекать из него значения функциями.

Зачем нужен тип JSON

Иногда у сущности есть гибкий набор полей, который неудобно раскладывать по столбцам: настройки пользователя, характеристики товара, метаданные. Раньше такое складывали в TEXT как строку, но тогда база не понимала структуру. Тип JSON решает это: он валидирует документ и даёт функции для доступа к полям.

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  settings JSON
);

INSERT INTO users (name, settings)
VALUES ('Анна', '{"theme": "dark", "notifications": true}');

Чтение значений из JSON

Извлечь поле можно функцией JSON_EXTRACT или коротким оператором -> / ->> (последний возвращает значение без кавычек).

SELECT name, settings->>'$.theme' AS theme
FROM users
WHERE settings->>'$.theme' = 'dark';

-- то же через функцию
SELECT JSON_EXTRACT(settings, '$.theme') FROM users;

Это MySQL-специфика, поэтому блоки текстовые: в учебной SQLite-песочнице синтаксис JSON-функций отличается.

Когда JSON, а когда обычные столбцы

JSON удобен, но это не замена нормальной схеме. Правило простое:

  • Обычные столбцы — если по полю ищут, фильтруют, сортируют, соединяют. Они индексируются и работают быстро.
  • JSON — для редко запрашиваемых, нерегулярных, «дополнительных» данных, структура которых меняется.

Не складывайте в JSON то, по чему постоянно фильтруете: реляционная модель для этого эффективнее.

Чек-лист выбора типа

ДанныеТип
Идентификатор, счётчикINT UNSIGNED (+ AUTO_INCREMENT для ключа)
ДеньгиDECIMAL(10,2)
Короткая строка (имя, email)VARCHAR(n)
Большой текст (статья)TEXT
Фиксированный набор статусовENUM или таблица-справочник
Дата созданияDATETIME / TIMESTAMP
Флаг да/нетTINYINT(1)
Гибкие метаданныеJSON

Переносимый пример

Сама идея «храним и выбираем настройки» работает и на обычных столбцах — что часто и лучше:

CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  name TEXT,
  theme TEXT,
  notifications INTEGER
);

INSERT INTO users (name, theme, notifications) VALUES
  ('Анна', 'dark', 1),
  ('Борис', 'light', 0);

SELECT name FROM users WHERE theme = 'dark';

Вывод:

name
Анна

Итог

  • Тип JSON валидирует документы и даёт функции (JSON_EXTRACT, ->>) для доступа к полям.
  • JSON — для гибких, редко запрашиваемых данных, а не для всего подряд.
  • То, по чему фильтруете и соединяете, держите в обычных индексируемых столбцах.
  • Выбор типа — это про корректность, место и скорость: берите минимально достаточный точный тип.
Проверьте себя
1. Когда тип JSON в MySQL — удачный выбор?
Aдля главного идентификатора строки
Bдля гибких, нерегулярных данных, по которым редко фильтруют
Cдля денежных сумм
Dдля всех текстовых полей подряд
2. Какая функция извлекает значение из JSON-столбца в MySQL?
ASUBSTRING
BJSON_EXTRACT
CCONCAT
DCAST
3. Почему поле, по которому постоянно фильтруют, лучше хранить отдельным столбцом, а не внутри JSON?
AJSON нельзя записать в MySQL
Bобычные столбцы индексируются и работают быстрее при поиске
CJSON занимает больше места всегда
Dстолбцы не поддерживают NULL
Поддержать проект