Рідна підтримка JSON в MYSQL 5.7: які плюси і мінуси типу даних JSON в MYSQL?


113

У 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 colum? Це добре? Чи порушує це нормалізація. Якщо це можливо, я думаю, він буде діяти як NoSQL у стовпці MySQL . Мені дуже хочеться дізнатися більше про цю особливість. Плюси і мінуси типу даних MySQL JSON.


о, будь ласка, не кажіть, що я думаю, що ви говорите. Ось прочитайте це . Ваш - це ще один варіант поганої ідеї.
Дрю

@Drew Ви дали велику відповідь. Але це не моє питання. Я просто хочу знати, що якщо ми пишемо запит на дані json, то ми можемо пропустити правила sql. Бо нам не потрібно багато таблиць
Імран

1
ти сказав Now it is possible to store more complex data in column. Будьте обережні
Дрю

2
Індекс підтримки типу даних Json і має розумний розмір: 64K & 4G. То яка проблема, якщо я хочу зберігати дані 2000 і додати 5 вкладених міток замість 5 таблиць із відношенням?
Імран

5
"Я дуже хочу дізнатися більше про цю особливість." і "Плюси і мінуси типу даних MySQL JSON". не є питаннями, і якщо їх перефразувати як запитання, вони занадто широкі. "Тому я ніколи не думаю про складну структуру схеми та зовнішні ключі в MySQL. Я зберігаю складні відносини, використовуючи лише кілька таблиць." є суперечливим, оскільки JSON не є відносинами та ФК. Пояснення "чи це добре" - це лише вступ до реляційної моделі, тому знову це занадто широко. Опрацюйте кілька прикладів, складіть свій власний список плюсів і мінусів із посиланнями та запитайте, де ви пішли не так.
філіпсі

Відповіді:


57
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. Тільки у списку вибору.

Коли ви посилаєтесь на стовпці в інших пунктах (ПРИЄДНУЙТЕСЯ, ДІЙ, ГРУПУВАТИ ВІД, ІМУЙТЕ, ЗАМОВЛЕННЯ), то ефективніше використовувати звичайні стовпці, а не поля в документах 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
Варто перейти за посиланням на слайди
Пол Кемпбелл

Хороша думка, що ці 2 технології є хорошими власними засобами, і ми вирішуємо, що відповідатимемо нашим потребам та що дає більше переваг щодо безпеки та ефективності.
Крістофер Пелайо

1
Суть проблеми полягає в тому, що ALTER TABLE все ще потрібен, щоб використовувати індекс на створеному стовпчику для кожного нового ключа JSON. Радий бачити, як це вказували.
user1454926

Тільки якщо вам потрібно додати віртуальний стовпець та / або індекс. Якщо ви ставитесь до даних JSON як до «чорної скриньки» і не намагаєтесь робити жодних запитів, які шукають чи сортують у підполях в межах JSON, то робити це вам не потрібно. Ось чому я рекомендую уникати посилань JSON в JOIN, WHEREабо інші положення. Просто заберіть стовпчик JSON у списку вибору.
Білл

Посилання на слайди порушено, @BillKarwin.
озера

43

Наступне з MySQL 5.7 повертає сексуальне зображення з JSON для мене добре:

Використання типу даних JSON у MySQL має дві переваги перед зберіганням рядків JSON у текстовому полі:

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

...

Спеціалізовані смаки магазинів NoSQL (БД документів, сховища ключових значень та графічні БД), ймовірно, є кращими варіантами для конкретних випадків їх використання, але додавання цього типу даних може допомогти вам зменшити складність вашої технології стеку. Ціна пов'язана з базами даних MySQL (або сумісними). Але це не проблема для багатьох користувачів.

Зверніть увагу на мову підтвердження документів, оскільки це важливий фактор. Я думаю, акумулятор тестів потрібно виконати для порівняння двох підходів. Ці два буття:

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

Зараз у мережі є неглибокі слайди на тему mysql / json / performance від того, що я бачу.

Можливо, ваша посада може стати центром для цього. Або, можливо, продуктивність - це думка, не впевнений, і ви просто раді не створювати купу таблиць.


7
Один кон; Тип даних JSON не підтримується таблицями пам'яті Mysql, як типи даних, TEXT & BLOB. Це означає, що якщо потрібна тимчасова таблиця, вона створить таблицю на основі диска, а не пам'ять. Окремі випадки, коли тут використовується тимчасова таблиця: dev.mysql.com/doc/refman/5.7/uk/internal-temporary-tables.html
raiz media

1
@raizmedia Чи не могли б ви пояснити, чому таблиця на основі диска є проблемою проти пам’яті (я думаю, що на основі таблиці)?
lapin

@lapin Напевно, через обмеження швидкості.
Маленький помічник

@LittleHelper ви можете цього уникнути, якщо використовувати слот M.2 для PCI 4x 40 Gb / s та вставити підтримуваний накопичувач 40 Gb / s. Це працює так само швидко, як пам’ять. Ви можете застосувати спеціальний формат до цього диска, який використовується для форматування пам'яті.
Сергій Романов

@SergeyRomanov, [citation required]Ви орієнтували цей диск на RAM?
Білл Карвін

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
Можливо, вам буде цікаво використовувати стовпець VIRTUAL. percona.com/blog/2016/03/07/…
Белл

10

З мого досвіду, реалізація JSON принаймні в MySql 5.7 не дуже корисна через низьку продуктивність. Ну, це не так вже й погано для читання даних та перевірки. Однак модифікація JSON у 10-20 разів повільніше для MySql, ніж для 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 або перевірити правопис? ;)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.