Prise en charge native de JSON dans MYSQL 5.7: quels sont les avantages et les inconvénients du type de données JSON dans MYSQL?

113

Dans MySQL 5.7, un nouveau type de données pour stocker des données JSON dans des tables MySQL a été ajouté. Ce sera évidemment un grand changement dans MySQL. Ils ont énuméré certains avantages

Validation de document - Seuls les documents JSON valides peuvent être stockés dans une colonne JSON, vous obtenez ainsi une validation automatique de vos données.

Accès efficace - Plus important encore, lorsque vous stockez un document JSON dans une colonne JSON, il n'est pas stocké en tant que valeur de texte brut. Au lieu de cela, il est stocké dans un format binaire optimisé qui permet un accès plus rapide aux membres d'objet et aux éléments du tableau.

Performances - Améliorez les performances de vos requêtes en créant des index sur les valeurs dans les colonnes JSON. Ceci peut être réalisé avec des «index fonctionnels» sur des colonnes virtuelles.

Commodité - La syntaxe en ligne supplémentaire pour les colonnes JSON rend très naturel l'intégration des requêtes Document dans votre SQL. Par exemple (features.feature est une colonne JSON):SELECT feature->"$.properties.STREET" AS property_street FROM features WHERE id = 121254;

HOU LA LA ! ils incluent quelques fonctionnalités intéressantes. Il est désormais plus facile de manipuler les données. Il est désormais possible de stocker des données plus complexes en colonne. MySQL est donc désormais parfumé avec NoSQL.

Maintenant, je peux imaginer une requête pour les données JSON quelque chose comme

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 );

Alors, puis-je stocker d'énormes petites relations dans quelques json colum? Est-ce bien? Cela brise-t-il la normalisation. Si cela est possible, je suppose que cela fonctionnera comme NoSQL dans une colonne MySQL . Je veux vraiment en savoir plus sur cette fonctionnalité. Avantages et inconvénients du type de données MySQL JSON.

Imran
la source
oh s'il vous plaît ne dites pas ce que je pense que vous dites. Ici, lisez ceci . Le vôtre est encore une autre variante d'une mauvaise idée.
Tiré
@Drew Vous avez donné une grande réponse. Mais ce n'est pas ma question. Je veux juste savoir que si nous écrivons une requête pour les données json, nous pouvons ignorer les règles SQL. car nous n'avons pas besoin de beaucoup de tables
Imran
1
vous avez dit Now it is possible to store more complex data in column. Soyez prudent
Tiré
2
Index de support de type de données Json et taille intelligente: 64K et 4G. Alors quel est le problème si je veux stocker 2000 données et ajouter 5 étiquettes imbriquées au lieu de 5 tables avec relation?
Imran
5
"Je veux vraiment en savoir plus sur cette fonctionnalité." et «Avantages et inconvénients du type de données MySQL JSON». ne sont pas des questions, et si elles sont reformulées comme des questions, elles sont trop larges. "Donc je ne pense jamais à une structure de schéma complexe et à des clés étrangères dans MySQL. Je stocke des relations complexes en utilisant seulement quelques tables." est auto-contradictoire puisque JSON n'est pas des relations et des FK. Une explication de «est-ce bien» est juste une introduction au modèle relationnel, donc encore une fois c'est trop large. Parcourez quelques exemples, faites votre propre liste des avantages et des inconvénients avec des références et demandez où vous vous êtes trompé.
philipxy

Réponses:

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

L'utilisation d'une colonne dans une expression ou une fonction comme celle-ci gâche toute chance que la requête utilise un index pour aider à optimiser la requête. La requête présentée ci-dessus est obligée de faire une analyse de table.

L'affirmation relative à un "accès efficace" est trompeuse. Cela signifie qu'après que la requête examine une ligne avec un document JSON, elle peut extraire un champ sans avoir à analyser le texte de la syntaxe JSON. Mais il faut toujours une analyse de table pour rechercher des lignes. En d'autres termes, la requête doit examiner chaque ligne.

Par analogie, si je recherche dans l'annuaire des personnes avec le prénom «Bill», je dois quand même lire toutes les pages de l'annuaire, même si les prénoms ont été mis en surbrillance pour les repérer un peu plus rapidement.

MySQL 5.7 vous permet de définir une colonne virtuelle dans la table, puis de créer un index sur la colonne virtuelle.

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

Ensuite, si vous interrogez la colonne virtuelle, elle peut utiliser l'index et éviter le balayage de table.

SELECT * FROM t1
WHERE series IN ...

C'est bien, mais cela manque un peu l'intérêt d'utiliser JSON. L'avantage de l'utilisation de JSON est qu'il vous permet d'ajouter de nouveaux attributs sans avoir à faire ALTER TABLE. Mais il s'avère que vous devez tout de même définir une colonne supplémentaire (virtuelle), si vous souhaitez rechercher des champs JSON à l'aide d'un index.

Mais vous n'êtes pas obligé de définir des colonnes et des index virtuels pour chaque champ du document JSON, uniquement ceux sur lesquels vous souhaitez rechercher ou trier. Il peut y avoir d'autres attributs dans le JSON que vous n'avez besoin d'extraire que dans la liste de sélection, comme suit:

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

Je dirais généralement que c'est la meilleure façon d'utiliser JSON dans MySQL. Uniquement dans la liste de sélection.

Lorsque vous référencez des colonnes dans d'autres clauses (JOIN, WHERE, GROUP BY, HAVING, ORDER BY), il est plus efficace d'utiliser des colonnes conventionnelles, et non des champs dans des documents JSON.

J'ai présenté une conférence intitulée Comment utiliser JSON dans MySQL Wrong lors de la conférence Percona Live en avril 2018. Je mettrai à jour et répéterai la conférence à Oracle Code One à l'automne.

Il y a d'autres problèmes avec JSON. Par exemple, dans mes tests, il a fallu 2-3 fois plus d'espace de stockage pour les documents JSON par rapport aux colonnes conventionnelles stockant les mêmes données.

MySQL fait la promotion de ses nouvelles capacités JSON de manière agressive, en grande partie pour dissuader les gens de migrer vers MongoDB. Mais le stockage de données orienté document comme MongoDB est fondamentalement un moyen non relationnel d'organiser les données. C'est différent du relationnel. Je ne dis pas que l'un est meilleur que l'autre, c'est juste une technique différente, adaptée à différents types de requêtes.

Vous devez choisir d'utiliser JSON lorsque JSON rend vos requêtes plus efficaces.

Ne choisissez pas une technologie simplement parce qu'elle est nouvelle ou pour des raisons de mode.


Edit: L'implémentation de la colonne virtuelle dans MySQL est censée utiliser l'index si votre clause WHERE utilise exactement la même expression que la définition de la colonne virtuelle. Autrement dit, ce qui suit doit utiliser l'index sur la colonne virtuelle, car la colonne virtuelle est définieAS (JSON_EXTRACT(data,"$.series"))

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

Sauf que j'ai trouvé en testant cette fonctionnalité qu'elle ne fonctionne PAS pour une raison quelconque si l'expression est une fonction d'extraction JSON. Cela fonctionne pour d'autres types d'expressions, mais pas pour les fonctions JSON.

Bill Karwin
la source
7
Ça vaut le coup de suivre le lien vers les diapositives
Paul Campbell
Bon point les 2 technologies sont toutes les deux bonnes dans leurs propres moyens nous décidons de celle qui répondra à nos besoins et de ce qui nous donne le plus d'avantages en termes de sécurité et de performance.
Christopher Pelayo
1
Le nœud du problème est qu'ALTER TABLE est toujours nécessaire pour utiliser un index sur une colonne générée pour chaque nouvelle clé dans le JSON. Heureux de le voir signalé.
user1454926
Uniquement si vous devez ajouter une colonne virtuelle et / ou un index. Si vous traitez les données JSON comme une "boîte noire" et n'essayez pas de faire des requêtes qui recherchent ou trient sur des sous-champs dans JSON, vous n'avez pas besoin de le faire. Voilà pourquoi je recommande d'éviter le référencement JSON dans JOIN, WHEREou d' autres clauses. Récupérez simplement la colonne JSON dans la liste de sélection.
Bill Karwin
Le lien vers les diapositives est rompu, @BillKarwin.
Lakesare
43

Ce qui suit de MySQL 5.7 me ramène sexy avec JSON :

L'utilisation du type de données JSON dans MySQL présente deux avantages par rapport au stockage de chaînes JSON dans un champ de texte:

La validation des données. Les documents JSON seront automatiquement validés et les documents invalides produiront une erreur. Amélioration du format de stockage interne. Les données JSON sont converties dans un format qui permet un accès en lecture rapide aux données dans un format structuré. Le serveur est capable de rechercher des sous-objets ou des valeurs imbriquées par clé ou index, ce qui permet une flexibilité et des performances accrues.

...

Les versions spécialisées des magasins NoSQL (bases de données de documents, magasins de valeurs clés et bases de données graphiques) sont probablement de meilleures options pour leurs cas d'utilisation spécifiques, mais l'ajout de ce type de données peut vous permettre de réduire la complexité de votre pile technologique. Le prix est le couplage aux bases de données MySQL (ou compatibles). Mais ce n'est pas un problème pour de nombreux utilisateurs.

Notez le langage concernant la validation des documents car il s'agit d'un facteur important. Je suppose qu'une batterie de tests doit être effectuée pour comparer les deux approches. Ces deux étant:

  1. Mysql avec les types de données JSON
  2. Mysql sans

Le net n'a que des diaporamas peu profonds pour le moment sur le sujet de mysql / json / performance d'après ce que je vois.

Peut-être que votre message peut être une plaque tournante pour cela. Ou peut-être que la performance est une réflexion après coup, pas sûr, et que vous êtes juste excité de ne pas créer un tas de tables.

A dessiné
la source
7
Un con; Le type de données JSON n'est pas pris en charge par les tables de mémoire Mysql, comme les types de données, TEXT & BLOB. Cela signifie que si une table temporaire est requise, elle créera une table basée sur le disque et non la mémoire. Certains cas d'utilisation d'une table temporaire sont décrits ici: dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html
raiz media
1
@raizmedia Pourriez-vous expliquer pourquoi une table basée sur disque est un problème par rapport à la mémoire (table basée je suppose)?
lapin
@lapin Probablement à cause des limitations de vitesse.
Little Helper
@LittleHelper vous pouvez l'éviter si vous utilisez le slot PCI 4x 40 Gb / s M.2 et insérez un disque pris en charge à 40 Gb / s. Cela fonctionne aussi vite que memmory. Vous pouvez également appliquer un format spécial à ce lecteur utilisé pour formater la mémoire.
Sergey Romanov
@SergeyRomanov, [citation required]avez-vous comparé ce lecteur à la RAM?
Bill Karwin le
11

J'ai récemment rencontré ce problème et je résume les expériences suivantes:

1, il n'y a pas de moyen de résoudre toutes les questions. 2, vous devez utiliser le JSON correctement.

Un cas:

J'ai une table nommée:, CustomFieldet elle doit avoir deux colonnes: name, fields. nameest une chaîne localisée, son contenu devrait ressembler à:

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

Et fieldsdevrait être comme ça:

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

Comme vous pouvez le voir, le nameet le fieldspeuvent être enregistrés au format JSON, et cela fonctionne!

Cependant, si j'utilise le namepour rechercher très fréquemment dans ce tableau, que dois-je faire? Utilisez le JSON_CONTAINS, JSON_EXTRACT...? De toute évidence, ce n'est pas une bonne idée de l' enregistrer comme JSON plus, nous devrions enregistrer à une table indépendante: CustomFieldName.

Dans le cas ci-dessus, je pense que vous devriez garder ces idées à l'esprit:

  1. Pourquoi MYSQL prend en charge JSON?
  2. Pourquoi voulez-vous utiliser JSON? Votre logique métier en avait-elle juste besoin? Ou il y a autre chose?
  3. Ne soyez jamais paresseux

Merci

Bruce
la source
2
Vous pourriez être intéressé par l'utilisation d'une colonne VIRTUELLE. percona.com/blog/2016/03/07/…
Bell
10

D'après mon expérience, l'implémentation JSON au moins dans MySql 5.7 n'est pas très utile en raison de ses mauvaises performances. Eh bien, ce n'est pas si mal pour la lecture des données et la validation. Cependant, la modification JSON est 10 à 20 fois plus lente avec MySql qu'avec Python ou PHP. Imaginons un JSON très simple:

{ "name": "value" }

Supposons que nous devions le convertir en quelque chose comme ça:

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

Vous pouvez créer un script simple avec Python ou PHP qui sélectionnera toutes les lignes et les mettra à jour une par une. Vous n'êtes pas obligé de faire une énorme transaction pour cela, donc d'autres applications pourront utiliser la table en parallèle. Bien sûr, vous pouvez également faire une énorme transaction si vous le souhaitez, vous aurez donc la garantie que MySql effectuera "tout ou rien", mais d'autres applications ne pourront probablement pas utiliser la base de données pendant l'exécution de la transaction.

J'ai une table de 40 millions de lignes et le script Python la met à jour en 3-4 heures.

Maintenant, nous avons MySql JSON, donc nous n'avons plus besoin de Python ou PHP, nous pouvons faire quelque chose comme ça:

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

Cela a l'air simple et excellent. Cependant, sa vitesse est 10 à 20 fois plus lente que la version Python et il s'agit d'une transaction unique, de sorte que les autres applications ne peuvent pas modifier les données de la table en parallèle.

Donc, si nous voulons simplement dupliquer la clé JSON dans une table de 40 millions de lignes, nous ne devons pas utiliser de table du tout pendant 30 à 40 heures. Cela n'a aucun sens.

À propos de la lecture des données, d'après mon expérience, l'accès direct au champ JSON via JSON_EXTRACTin WHEREest également extrêmement lent (beaucoup plus lent TEXTqu'avec une LIKEcolonne non indexée). Les colonnes générées virtuelles fonctionnent beaucoup plus rapidement, cependant, si nous connaissons notre structure de données à l'avance, nous n'avons pas besoin de JSON, nous pouvons utiliser des colonnes traditionnelles à la place. Lorsque nous utilisons JSON là où c'est vraiment utile, c'est-à-dire lorsque la structure des données est inconnue ou change souvent (par exemple, les paramètres de plug-in personnalisés), la création régulière de colonnes virtuelles pour d'éventuelles nouvelles colonnes ne semble pas être une bonne idée.

Python et PHP font de la validation JSON un charme, il est donc douteux que nous ayons besoin d'une validation JSON du côté de MySql. Pourquoi ne pas valider également les documents XML, Microsoft Office ou vérifier l'orthographe? ;)

Vitalii
la source