Встроенная поддержка JSON в MYSQL 5.7: каковы плюсы и минусы типа данных JSON в MYSQL?

114

В MySQL 5.7 был добавлен новый тип данных для хранения данных JSON в таблицах MySQL . Очевидно, это будет большое изменение в MySQL. Они перечислили некоторые преимущества

Проверка документов - в столбце JSON могут храниться только действительные документы JSON, поэтому вы получаете автоматическую проверку ваших данных.

Эффективный доступ - что еще более важно, когда вы храните документ JSON в столбце JSON, он не сохраняется в виде обычного текстового значения. Вместо этого он хранится в оптимизированном двоичном формате, который обеспечивает более быстрый доступ к элементам объекта и элементам массива.

Производительность - повысьте производительность запросов, создав индексы для значений в столбцах JSON. Этого можно добиться с помощью «функциональных индексов» виртуальных столбцов.

Удобство - дополнительный встроенный синтаксис для столбцов JSON делает очень естественным интеграцию запросов документов в ваш SQL. Например (features.feature - это столбец JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

ВОТ ЭТО ДА ! они включают в себя несколько замечательных функций. Теперь манипулировать данными стало проще. Теперь в столбце можно хранить более сложные данные. Итак, MySQL теперь приправлен NoSQL.

Теперь я могу представить запрос данных JSON примерно так:

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN 
( 
SELECT JSON_EXTRACT(data,"$.inverted") 
FROM t1 | {"series": 3, "inverted": 8} 
WHERE JSON_EXTRACT(data,"$.inverted")<4 );

Так могу ли я хранить огромные маленькие отношения в нескольких столбцах json? Это хорошо? Это нарушает нормализацию. Если это возможно, я думаю, он будет действовать как NoSQL в столбце MySQL . Я действительно хочу узнать больше об этой функции. Плюсы и минусы типа данных MySQL JSON.

Имран
источник
о, пожалуйста, не говори то, что я думаю, ты говоришь. Вот, прочтите это . Ваш - еще один вариант плохой идеи.
Дрю
@Drew Вы дали большой ответ. Но это не мой вопрос. Я просто хочу знать, что если мы напишем запрос для данных json, мы можем пропустить правила sql. потому что нам не нужно много столов
Имран
1
ты сказал Now it is possible to store more complex data in column. Будьте осторожны
Дрю
2
Индекс поддержки типа данных Json и имеет разумный размер: 64 КБ и 4G. Так в чем проблема, если я хочу сохранить 2000 данных и добавить 5 вложенных меток вместо 5 таблиц с отношением?
Имран
5
«Я действительно хочу узнать больше об этой функции». и «Плюсы и минусы типа данных MySQL JSON». не являются вопросами, и если их перефразировать как вопросы, они будут слишком широкими. «Поэтому я никогда не думаю о сложной структуре схемы и внешних ключах в MySQL. Я храню сложные отношения, используя всего несколько таблиц». противоречиво, поскольку JSON не является отношениями и FK. Объяснение «это хорошо?» - это просто введение в реляционную модель, так что опять же это слишком широко. Проработайте несколько примеров, составьте собственный список плюсов и минусов со ссылками и спросите, где вы ошиблись.
Филипси 06

Ответы:

58
SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

Использование столбца внутри выражения или функции, подобной этой, портит любую возможность запроса с использованием индекса для оптимизации запроса. Запрос, показанный выше, принудительно выполняет сканирование таблицы.

Утверждение об «эффективном доступе» вводит в заблуждение. Это означает, что после того, как запрос исследует строку с документом JSON, он может извлечь поле без необходимости анализировать текст синтаксиса JSON. Но для поиска строк по-прежнему требуется сканирование таблицы. Другими словами, запрос должен проверять каждую строку.

По аналогии, если я ищу в телефонной книге людей с именем «Билл», мне все равно придется читать каждую страницу в телефонной книге, даже если имена были выделены, чтобы их можно было быстрее обнаружить.

MySQL 5.7 позволяет вам определить виртуальный столбец в таблице, а затем создать индекс для виртуального столбца.

ALTER TABLE t1
  ADD COLUMN series AS (JSON_EXTRACT(data, '$.series')),
  ADD INDEX (series);

Затем, если вы запросите виртуальный столбец, он может использовать индекс и избежать сканирования таблицы.

SELECT * FROM t1
WHERE series IN ...

Это хорошо, но в нем упускается смысл использования JSON. Привлекательная часть использования JSON заключается в том, что он позволяет добавлять новые атрибуты без необходимости выполнять ALTER TABLE. Но оказывается, что вам все равно нужно определить дополнительный (виртуальный) столбец, если вы хотите искать поля JSON с помощью индекса.

Но вам не нужно определять виртуальные столбцы и индексы для каждого поля в документе JSON - только для тех, по которым вы хотите выполнять поиск или сортировку. В JSON могут быть и другие атрибуты, которые вам нужно только извлечь в списке выбора, например:

SELECT JSON_EXTRACT(data, '$.series') AS series FROM t1
WHERE <other conditions>

Я бы сказал, что это лучший способ использовать JSON в MySQL. Только в списке выбора.

Когда вы ссылаетесь на столбцы в других предложениях (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), более эффективно использовать обычные столбцы, а не поля в документах JSON.

Я представил доклад под названием " Как использовать JSON в MySQL неправильно" на конференции Percona Live в апреле 2018 года. Осенью я обновлюсь и повторю доклад на Oracle Code One.

Есть и другие проблемы с JSON. Например, в моих тестах требовалось в 2-3 раза больше места для хранения документов JSON по сравнению с обычными столбцами, в которых хранятся те же данные.

MySQL агрессивно продвигает свои новые возможности JSON, в основном, чтобы отговорить людей от перехода на MongoDB. Но документно-ориентированное хранилище данных, такое как MongoDB, по сути, является нереляционным способом организации данных. Это отличается от отношений. Я не говорю, что один лучше другого, это просто другая техника, подходящая для разных типов запросов.

Вам следует выбрать использование JSON, когда JSON делает ваши запросы более эффективными.

Не выбирайте технологию только потому, что она нова или ради моды.


Изменить: реализация виртуального столбца в MySQL должна использовать индекс, если ваше предложение WHERE использует точно такое же выражение, что и определение виртуального столбца. То есть следующее должно использовать индекс для виртуального столбца, поскольку виртуальный столбец определенAS (JSON_EXTRACT(data,"$.series"))

SELECT * FROM t1
WHERE JSON_EXTRACT(data,"$.series") IN ...

За исключением того, что при тестировании этой функции я обнаружил, что она НЕ работает по какой-то причине, если выражение является функцией извлечения JSON. Он работает для других типов выражений, но не для функций JSON.

Билл Карвин
источник
7
Стоит перейти по ссылке на слайды
Пол Кэмпбелл
Хороший момент: обе технологии хороши сами по себе. Это означает, что мы решаем, какая из них будет соответствовать нашим потребностям, а какая дает нам больше преимуществ с точки зрения безопасности и производительности.
Кристофер Пелайо
1
Суть проблемы в том, что ALTER TABLE по-прежнему необходим для использования индекса в сгенерированном столбце для каждого нового ключа в JSON. Рад видеть, что на это указывают.
user1454926
Только если вам нужно добавить виртуальный столбец и / или индекс. Если вы относитесь к данным JSON как к «черному ящику» и не пытаетесь выполнять какие-либо запросы с поиском или сортировкой по подполям в JSON, то этого делать не нужно. Вот почему я рекомендую избегать ссылок JSON в JOIN, WHEREили другие положения. Просто выберите столбец JSON в списке выбора.
Билл Карвин
Ссылка на слайды не работает, @BillKarwin.
lakesare
43

Следующее из MySQL 5.7 возвращает сексуальность с JSON, и мне это нравится:

Использование типа данных JSON в MySQL дает два преимущества по сравнению с хранением строк JSON в текстовом поле:

Валидация данных. Документы JSON будут автоматически проверены, а недействительные документы вызовут ошибку. Улучшенный формат внутреннего хранилища. Данные JSON преобразуются в формат, обеспечивающий быстрый доступ для чтения к данным в структурированном формате. Сервер может искать подобъекты или вложенные значения по ключу или индексу, что обеспечивает дополнительную гибкость и производительность.

...

Специализированные разновидности хранилищ NoSQL (базы данных документов, хранилища значений ключей и базы данных Graph), вероятно, являются лучшими вариантами для их конкретных случаев использования, но добавление этого типа данных может позволить вам снизить сложность вашего технологического стека. Цена связана с базами данных MySQL (или совместимыми). Но для многих это не проблема.

Обратите внимание на формулировку о проверке документов, поскольку это важный фактор. Я полагаю, что для сравнения этих двух подходов необходимо провести ряд тестов. Эти двое:

  1. Mysql с типами данных JSON
  2. MySQL без

На данный момент в сети есть лишь неглубокие слайд-шоу по теме mysql / json / performance из того, что я вижу.

Возможно, ваш пост станет для этого центром. Или, возможно, производительность - это после размышлений, не уверен, и вы просто рады, что не создаете кучу таблиц.

Нарисовался
источник
7
Один минус; Тип данных JSON не поддерживается таблицами Mysql Memory, как и типы данных TEXT и BLOB. Это означает, что если требуется временная таблица, она создаст таблицу на диске, а не в памяти. Некоторые случаи использования временной таблицы описаны здесь: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media
1
@raizmedia Не могли бы вы уточнить, почему таблица на диске является проблемой по сравнению с памятью (я думаю, на основе таблицы)?
Lapin
@lapin Вероятно из-за ограничения скорости.
Little Helper
@LittleHelper, вы можете избежать этого, если вы используете слот PCI 4x 40 Гбит / с M.2 и вставляете поддерживаемый диск 40 Гбит / с. Это работает так же быстро, как память. Вы также можете применить специальный формат к этому диску, который используется для форматирования памяти.
Сергей Романов
@SergeyRomanov, [citation required]Вы сравнивали этот диск с оперативной памятью?
Билл Карвин,
11

Я недавно столкнулся с этой проблемой и резюмирую следующие моменты:

1. Нет способа решить все вопросы. 2. Вы должны правильно использовать JSON.

Один случай:

У меня есть таблица с именем:, CustomFieldи в ней должны быть два столбца: name, fields. name- это локализованная строка, ее содержимое должно быть таким:

{
  "en":"this is English name",
  "zh":"this is Chinese name"
   ...(other languages)
}

И fieldsдолжно быть так:

[
  {
    "filed1":"value",
    "filed2":"value"
    ...
  },
  {
    "filed1":"value",
    "filed2":"value"
    ...
  }
  ...
]

Как вы можете видеть, как nameи fieldsмогут быть сохранены в формате JSON, и это работает!

Однако, если я nameочень часто использую для поиска в этой таблице, что мне делать? Используйте JSON_CONTAINS, JSON_EXTRACT...? Очевидно, что это не очень хорошая идея , чтобы сохранить его как JSON больше, мы должны сохранить его в независимой таблице CustomFieldName.

Из приведенного выше случая, я думаю, вам следует иметь в виду следующие идеи:

  1. Почему MYSQL поддерживает JSON?
  2. Почему вы хотите использовать JSON? Это просто нужно вашей бизнес-логике? Или есть еще что-то?
  3. Никогда не лениться

Спасибо

Брюс
источник
2
Возможно, вас заинтересует ВИРТУАЛЬНЫЙ столбец. percona.com/blog/2016/03/07/…
Bell
10

По моему опыту, реализация JSON, по крайней мере, в MySql 5.7 не очень полезна из-за ее низкой производительности. Что ж, это не так уж и плохо для чтения данных и проверки. Однако модификация JSON с MySql в 10-20 раз медленнее, чем с Python или PHP. Представим себе очень простой JSON:

{ "name": "value" }

Предположим, нам нужно преобразовать его во что-то вроде этого:

{ "name": "value", "newName": "value" }

Вы можете создать простой скрипт с Python или PHP, который будет выбирать все строки и обновлять их одну за другой. Вы не обязаны совершать для него одну огромную транзакцию, поэтому другие приложения могут использовать эту таблицу параллельно. Конечно, вы также можете сделать одну огромную транзакцию, если хотите, так что вы получите гарантию, что MySql выполнит «все или ничего», но другие приложения, скорее всего, не смогут использовать базу данных во время выполнения транзакции.

У меня есть таблица с 40 миллионами строк, и скрипт Python обновляет ее за 3-4 часа.

Теперь у нас есть MySql JSON, поэтому нам больше не нужны Python или PHP, мы можем сделать что-то вроде этого:

UPDATE `JsonTable` SET `JsonColumn` = JSON_SET(`JsonColumn`, "newName", JSON_EXTRACT(`JsonColumn`, "name"))

Смотрится просто и отлично. Однако его скорость в 10-20 раз ниже, чем у версии Python, и это единичная транзакция, поэтому другие приложения не могут изменять данные таблицы параллельно.

Итак, если мы хотим просто продублировать JSON-ключ в таблице из 40 миллионов строк, нам нужно вообще не использовать таблицу в течение 30-40 часов. В этом нет смысла.

Что касается чтения данных, по моему опыту, прямой доступ к полю JSON через JSON_EXTRACTin WHEREтакже очень медленный (намного медленнее, чем TEXTс LIKEнеиндексированным столбцом). Виртуально сгенерированные столбцы работают намного быстрее, однако, если мы заранее знаем нашу структуру данных, нам не нужен JSON, вместо этого мы можем использовать традиционные столбцы. Когда мы используем JSON там, где это действительно полезно, то есть когда структура данных неизвестна или часто меняется (например, настройки пользовательского плагина), создание виртуальных столбцов на регулярной основе для любых возможных новых столбцов не выглядит хорошей идеей.

Python и PHP делают проверку JSON как шарм, поэтому сомнительно, нужна ли нам вообще проверка JSON на стороне MySql. Почему бы также не проверить XML, документы Microsoft Office или проверить орфографию? ;)

Vitalii
источник