web-dev-qa-db-fra.com

Stocker des données dans MySQL en JSON

Je pensais que c'était une chose à faire. Et alors, je ne l'ai jamais fait. Ensuite, j'ai vu que FriendFeed avait fait cela et avait amélioré leur balance DB et réduit la latence. Je suis curieux de savoir si je devrais le faire. Et si oui, quelle est la bonne façon de le faire?

En gros, quel est le bon endroit pour apprendre à tout stocker dans MySQL en tant que base de données CouchDB? Tout stocker au format JSON semble être plus facile et plus rapide (ne pas construire, moins de latence).

De plus, est-il facile de modifier, supprimer, etc. des éléments stockés au format JSON sur la base de données?

102
Oscar Godson

CouchDB et MySQL sont deux bêtes très différentes. JSON est le moyen natif de stocker des éléments dans CouchDB. Dans MySQL, le mieux que vous puissiez faire est de stocker les données JSON sous forme de texte dans un seul champ. Cela irait totalement à l'encontre du but de le stocker dans un SGBDR et compliquerait grandement toutes les transactions de base de données.

Non.

Cela dit, FriendFeed semblait utiliser un schéma extrêmement personnalisé au-dessus de MySQL. Cela dépend vraiment de ce que vous voulez exactement stocker, il n’ya pratiquement pas de réponse définitive quant à la manière d’abuser d’un système de base de données, ce qui est donc logique pour vous. Étant donné que l'article est très ancien et que leur principale raison d'être contre Mongo et Couch était leur manque de maturité, je réévaluerais ces deux-là si MySQL ne vous en donne pas les moyens. Ils devraient avoir beaucoup grandi maintenant.

55
deceze

Tout le monde semble faire des commentaires sous un mauvais angle. Il est préférable de stocker du code JSON via PHP dans une base de données relationnelle. Il sera en effet plus rapide de charger et d'afficher des données complexes comme celle-ci. Cependant, vous aurez considérations de conception telles que la recherche, l'indexation, etc.

Pour ce faire, le meilleur moyen consiste à utiliser des données hybrides. Par exemple, si vous devez effectuer une recherche en fonction de la date et de l'heure, MySQL (performances optimisées) sera beaucoup plus rapide que PHP et pour quelque chose comme une recherche à distance des lieux, MySQL devrait également être beaucoup plus rapide (remarquez que la recherche n’accède pas). Les données sur lesquelles vous n'avez pas besoin de chercher peuvent ensuite être stockées au format JSON, BLOB ou dans tout autre format que vous jugerez vraiment nécessaire.

Les données auxquelles vous avez besoin d'accéder sont très facilement stockées au format JSON, par exemple un système de base de facturation au cas par cas. Ils ne profitent pas beaucoup du SGBDR, et pourraient être stockés dans JSON uniquement par json_encoding ($ _ POST ['entires']) si vous avez la structure de formulaire HTML correcte. 

Je suis heureux que vous soyez heureux d’utiliser MongoDB et j’espère que cela continuera à vous servir, mais ne croyez pas que MySQL vous échappera toujours, car la complexité de votre application augmentant, vous risquez de nécessiter un SGBDR pour certaines fonctionnalités et fonctionnalités (même s'il ne s'agit que de supprimer des données archivées ou des rapports commerciaux)

MySQL 5.7 prend désormais en charge un type de données JSON natif similaire à MongoDB et à d'autres magasins de données de documents sans schéma:

Support JSON

Depuis MySQL 5.7.8, MySQL prend en charge un type JSON natif. Les valeurs JSON ne sont pas stockées sous forme de chaînes, mais utilisent un format binaire interne permettant un accès en lecture rapide aux éléments de document. Les documents JSON stockés dans des colonnes JSON sont automatiquement validés chaque fois qu'ils sont insérés ou mis à jour, un document non valide générant une erreur. Les documents JSON sont normalisés à la création et peuvent être comparés à l'aide de la plupart des opérateurs de comparaison tels que =, <, <=,>,> =, <>,! = Et <=>; pour plus d'informations sur les opérateurs pris en charge, ainsi que sur les règles de priorité et autres que MySQL respecte lors de la comparaison de valeurs JSON, reportez-vous à la section Comparaison et ordre des valeurs JSON.

MySQL 5.7.8 introduit également un certain nombre de fonctions permettant d’utiliser les valeurs JSON. Ces fonctions incluent celles énumérées ici:

  1. Fonctions qui créent des valeurs JSON: JSON_ARRAY (), JSON_MERGE () et JSON_OBJECT (). Reportez-vous à la Section 12.16.2, «Fonctions créant des valeurs JSON».
  2. Fonctions de recherche dans les valeurs JSON: JSON_CONTAINS (), JSON_CONTAINS_PATH (), JSON_EXTRACT (), JSON_KEYS () et JSON_SEARCH (). Reportez-vous à la Section 12.16.3, «Fonctions de recherche de valeurs JSON».
  3. Fonctions qui modifient les valeurs JSON: JSON_APPEND (), JSON_ARRAY_APPEND (), JSON_ARRAY_INSERT (), JSON_INSERT (), JSON_QUOTE (), JSON_REMOVE (), JSON_REPLACE (), JSON_SEMPLE (), JSON_SET () et JSON_UNQUOTE (). Reportez-vous à la Section 12.16.4, «Fonctions modifiant les valeurs JSON».
  4. Fonctions fournissant des informations sur les valeurs JSON: JSON_DEPTH (), JSON_LENGTH (), JSON_TYPE () et JSON_VALID (). Reportez-vous à la Section 12.16.5, «Fonctions renvoyant des attributs de valeur JSON».

Dans MySQL 5.7.9 et versions ultérieures, vous pouvez utiliser column-> path comme raccourci pour JSON_EXTRACT (column, path). Cela fonctionne comme un alias pour une colonne lorsqu'un identificateur de colonne peut apparaître dans une instruction SQL, y compris les clauses WHERE, ORDER BY et GROUP BY. Cela inclut les commandes SELECT, UPDATE, DELETE, CREATE TABLE et autres instructions SQL. Le côté gauche doit être un identifiant de colonne JSON (et non un alias). Le côté droit est une expression de chemin JSON citée qui est évaluée par rapport au document JSON renvoyé en tant que valeur de colonne.

Reportez-vous à la Section 12.16.3, «Fonctions de recherche des valeurs JSON», pour plus d'informations sur les options -> et JSON_EXTRACT (). Pour plus d'informations sur la prise en charge des chemins JSON dans MySQL 5.7, reportez-vous à la section Recherche et modification de valeurs JSON. Voir aussi Index secondaires et colonnes virtuelles générées.

Plus d'informations:

https://dev.mysql.com/doc/refman/5.7/en/json.html

56
eecue

les caractères json n'ont rien de spécial quand il s'agit de stockage, des caractères tels que 

{, }, [, ], ', a-z, 0-9 ..... sont vraiment rien de spécial et peuvent être stockés sous forme de texte.

le premier problème que vous allez avoir est-ce

{ profile_id: 22, nom d'utilisateur: 'Robert', mot de passe: 'skhgeeht893htgn34ythg9er' }

la mise à jour de la mémoire stockée dans une base de données n’est pas aussi simple, sauf si vous aviez votre propre procédure et développé un code jsondecode pour mysql.

UPDATE users SET JSON(user_data,'username') = 'New User';

Donc, comme vous ne pouvez pas le faire, vous devez d’abord sélectionner le json, le décoder, le changer, le mettre à jour. En théorie, vous pourriez donc aussi passer plus de temps à construire une structure de base de données appropriée!

J'utilise json pour stocker des données, mais uniquement des métadonnées, des données qui ne sont pas régulièrement mises à jour, non liées à l'utilisateur. Par exemple, si un utilisateur ajoute une publication, et dans cette publication, il ajoute des images, analyse les images et crée des vignettes et puis utilisez les URL de pouce dans un format JSON.

24
RobertPitt

Pour illustrer la difficulté d'obtenir des données JSON à l'aide d'une requête, je vais partager la requête que j'ai faite pour gérer cela.

Il ne prend pas en compte les tableaux ou autres objets, mais uniquement les types de données de base. Vous devez remplacer les 4 occurrences de column par le nom de la colonne stockant le JSON et remplacer les 4 occurrences de myfield par le champ JSON auquel vous souhaitez accéder.

SELECT
    SUBSTRING(
        REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', ''),
        LOCATE(
            CONCAT('myfield', ':'),
            REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', '')
        ) + CHAR_LENGTH(CONCAT('myfield', ':')),
        LOCATE(
            ',',
            SUBSTRING(
                REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', ''),
                LOCATE(
                    CONCAT('myfield', ':'),
                    REPLACE(REPLACE(REPLACE(column, '{', ''), '}', ','), '"', '')
                ) + CHAR_LENGTH(CONCAT('myfield', ':'))
            )
        ) - 1
    )
    AS myfield
FROM mytable WHERE id = '3435'
14
Jorjon

C'est une vieille question, mais je suis toujours capable de voir cela en haut du résultat de recherche de Google. Je suppose donc qu'il serait utile d'ajouter une nouvelle réponse 4 ans après que la question a été posée.

Tout d’abord, il existe un meilleur support pour le stockage de JSON dans le SGBDR. Vous pouvez envisager de passer à PostgreSQL (bien que MySQL prenne en charge JSON depuis la v5.7.7). PostgreSQL utilise des commandes SQL très similaires à celles de MySQL, à la différence qu’elles supportent davantage de fonctions. L’une des fonctions qu’ils ont ajoutées est qu’elles fournissent un type de données JSON et que vous pouvez désormais interroger le JSON stocké. ( Quelques références à ce sujet ) Si vous ne créez pas la requête directement dans votre programme, par exemple, en utilisant PDO en php ou éloquent en Laravel, il vous suffit d'installer PostgreSQL sur votre serveur et de le modifier. paramètres de connexion de base de données. Vous n'avez même pas besoin de changer votre code.

Comme le suggéraient les autres réponses, la plupart du temps, stocker des données au format JSON directement dans le SGBDR n'est pas une bonne idée. Il y a cependant quelques exceptions. Une situation à laquelle je peux penser est un champ avec un nombre variable d'entrées liées. 

Par exemple, pour stocker les balises d'un article de blog, vous devez normalement disposer d'un tableau pour les articles de blog, d'un tableau de balises et d'un tableau correspondant. Ainsi, lorsque l'utilisateur souhaite modifier une publication et que vous devez afficher la balise associée à cette publication, vous devez interroger 3 tables. Cela nuira beaucoup à la performance si votre table/table de correspondance est longue. 

En stockant les balises au format JSON dans la table de publication de blog, la même action ne nécessite qu'une seule recherche de table. L'utilisateur pourra alors voir la publication du blog pour être modifiée plus rapidement, mais cela nuira à la performance si vous souhaitez créer un rapport sur la publication liée à une balise, ou éventuellement effectuer une recherche par balise.

Vous pouvez également essayer de dénormaliser la base de données. En dupliquant les données et en les stockant des deux manières, vous pouvez bénéficier des deux méthodes. Vous aurez juste besoin d'un peu plus de temps pour stocker vos données et plus d'espace de stockage (ce qui est peu coûteux comparé au coût d'une plus grande puissance de calcul)

9
cytsunny

Cela dépend vraiment de votre cas d'utilisation. Si vous stockez des informations qui n'ont absolument aucune valeur dans les rapports et ne sont pas interrogées via des commandes JOIN avec d'autres tables, il peut s'avérer judicieux de stocker vos données dans un seul champ de texte, codé au format JSON.

Cela pourrait grandement simplifier votre modèle de données. Cependant, comme l'a mentionné RobertPitt, ne vous attendez pas à pouvoir combiner ces données avec d'autres données normalisées.

9
Phil LaNasa

Je dirais que les deux seules raisons pour considérer ceci sont:

  • les performances ne suffisent pas avec une approche normalisée
  • vous ne pouvez pas facilement modéliser vos données particulièrement fluides/flexibles/changeantes

J'ai écrit un peu sur ma propre approche ici:

Quels problèmes d'évolutivité avez-vous rencontrés lors de l'utilisation d'un magasin de données NoSQL?

(voir la réponse en haut)

Même JSON n’était pas assez rapide, nous avons donc opté pour un format de texte personnalisé. A travaillé/continue de bien fonctionner pour nous. 

Y a-t-il une raison pour laquelle vous n'utilisez pas quelque chose comme MongoDB? (pourrait être que MySQL est "obligatoire"; juste curieux)

8
Brian

Il me semble que tout le monde qui répond à cette question est en quelque sorte absent de l'un des problèmes critiques, sauf que @deceze - utilise le bon outil pour le travail . Vous pouvez forcer une base de données relationnelle à stocker presque tout type de données et forcer Mongo à gérer des données relationnelles, mais à quel prix? Vous finissez par introduire la complexité à tous les niveaux de développement et de maintenance, de la conception du schéma au code d'application; sans parler de la performance frappé.

En 2014, nous avons accès à de nombreux serveurs de base de données qui gèrent de manière exceptionnelle des types de données spécifiques. 

  • Mongo (stockage de documents)
  • Redis (stockage de données clé-valeur)
  • MySQL/Maria/PostgreSQL/Oracle/etc (données relationnelles)
  • CouchDB (JSON)

Je suis sûr que d'autres, comme RabbirMQ et Cassandra, m'ont échappé. Mon point est, utilisez le bon outil pour les données que vous devez stocker. 

Si votre application nécessite le stockage et la récupération d'une variété de données, très, très vite (et qui ne l'ignore pas), n'hésitez pas à utiliser plusieurs sources de données pour une application. Les infrastructures Web les plus courantes prennent en charge plusieurs sources de données (Rails, Django, Grails, Cake, Zend, etc.). Cette stratégie limite la complexité à un domaine spécifique de l'application, à l'ORM ou à l'interface de source de données de l'application.

5
CheddarMonkey

Voici une fonction permettant de sauvegarder/mettre à jour les clés d’un tableau JSON dans une colonne et une autre fonction permettant d’extraire des valeurs JSON. Ces fonctions sont créées en supposant que le nom de la colonne de stockage du tableau JSON est json. Il utilise PDO.

Fonction de sauvegarde/mise à jour

function save($uid, $key, $val){
 global $dbh; // The PDO object
 $sql = $dbh->prepare("SELECT `json` FROM users WHERE `id`=?");
 $sql->execute(array($uid));
 $data      = $sql->fetch();
 $arr       = json_decode($data['json'],true);
 $arr[$key] = $val; // Update the value
 $sql=$dbh->prepare("UPDATE `users` SET `json`=? WHERE `id`=?");
 $sql->execute(array(
   json_encode($arr), 
   $uid
 ));
}

$ uid est l'identifiant de l'utilisateur, $ key - la clé JSON à mettre à jour et sa valeur est mentionnée sous la forme $ val.

Fonction Get Value

function get($uid, $key){
 global $dbh;
 $sql = $dbh->prepare("SELECT `json` FROM `users` WHERE `id`=?");
 $sql->execute(array($uid));
 $data = $sql->fetch();
 $arr  = json_decode($data['json'], true);
 return $arr[$key];
}

$ key est une clé de JSON tableau à partir duquel nous avons besoin de la valeur.

5
Subin

La prise en charge précoce du stockage de JSON dans MySQL a été ajoutée à la version de MySQL 5.7.7 JSON Labs } _ ( binaires Linux _, source )! La version semble avoir été développée à partir d’une série de fonctions définies par l’utilisateur et liées au JSON rendues publiques retour en 2013 .

Ce support JSON natif naissant semble aller dans une direction très positive, comprenant la validation JSON sur INSERT, un format de stockage binaire optimisé comprenant une table de consultation dans le préambule qui permet à la fonction JSN_EXTRACT d'effectuer des recherches binaires plutôt que d'analyser chaque accès. Il existe également toute une série de nouvelles fonctions permettant de gérer et d'interroger des types de données JSON spécifiques:

CREATE TABLE users (id INT, preferences JSON);

INSERT INTO users VALUES (1, JSN_OBJECT('showSideBar', true, 'fontSize', 12));

SELECT JSN_EXTRACT(preferences, '$.showSideBar') from users;

+--------------------------------------------------+
| id   | JSN_EXTRACT(preferences, '$.showSideBar') |
+--------------------------------------------------+
| 1    | true                                      |
+--------------------------------------------------+

IMHO, ce qui précède est un excellent cas d'utilisation de cette nouvelle fonctionnalité; De nombreuses bases de données SQL possèdent déjà une table utilisateur et, plutôt que de procéder à des modifications de schéma sans fin pour prendre en charge un ensemble évolutif de préférences utilisateur, il est parfait de disposer d'une seule colonne JSON à une seule variable JOIN. D'autant plus qu'il est peu probable qu'il soit nécessaire de le consulter pour des éléments individuels.

Bien qu'il soit encore tôt dans la vie, l'équipe de serveurs MySQL communique les modifications onleblog .

2
Rich Pollock

JSON est également un type de données valide dans la base de données PostgreSQL. Cependant, la base de données MySQL n'a pas encore officiellement pris en charge JSON. Mais cuire: http://mysqlserverteam.com/json-labs-release-native-json-data-type-and-binary-format/

Je conviens également qu'il existe de nombreux cas valables selon lesquels certaines données doivent être sérialisées en chaîne dans une base de données. La raison principale peut en être quand il n'est pas interrogé régulièrement et que son propre schéma peut changer - vous ne voulez pas changer le schéma de base de données correspondant à cela. La deuxième raison est que lorsque la chaîne sérialisée provient directement de sources externes, vous ne voudrez peut-être pas toutes les analyser et les insérer dans la base de données à tout prix jusqu'à ce que vous en utilisiez une. J'attendrai donc que la nouvelle version de MySQL prenne en charge JSON, car il sera alors plus facile de basculer entre différentes bases de données.

2
Cherry Qianyu Liu

Je sais que c'est vraiment tard, mais dans une situation similaire, j'ai utilisé une approche hybride consistant à maintenir les normes du SGBDR en normalisant les tables jusqu'à un point, puis à stocker les données au format JSON en tant que valeur textuelle au-delà de ce point. Ainsi, par exemple, je stocke des données dans 4 tables suivant les règles de normalisation des SGBDR. Cependant, dans la 4ème table pour accueillir le schéma dynamique, je stocke les données au format JSON. À chaque fois que je veux récupérer des données, je récupère les données JSON, les analyse et les affiche en Java. Cela a fonctionné pour moi jusqu'à présent et pour m'assurer que je suis toujours capable d'indexer les champs que je transforme en données JSON dans le tableau de manière normalisée à l'aide d'un ETL. Cela garantit que pendant que l'utilisateur travaille sur l'application, il est confronté à un retard minimal et que les champs sont transformés en un format convivial pour l'analyse de données, etc. Je pense que cette approche fonctionne bien et je pense que MYSQL (5.7+) permet également l'analyse de JSON. Cette approche vous offre les avantages des bases de données SGBDR et NOSQL.

1
prashant

J'utilise json pour enregistrer n'importe quoi pour un projet, j'utilise en fait trois tables! une pour les données de json, une pour l'index de chaque métadonnée de la structure de json (chaque méta est codée par un identifiant unique) et une pour l'utilisateur de session, c'est tout . Le repère ne peut pas être quantifié à ce stade état du code, mais par exemple j’étais vue d’utilisateur (jointure interne avec index) pour obtenir une catégorie (ou quoi que ce soit, en tant qu’utilisateur, ...), et elle était très lente (très très lente, la vue utilisée dans mysql n’est pas la Le module de recherche, dans cette structure, peut faire tout ce que je veux, mais je pense que mongodb sera plus efficace dans ce concept d’enregistrement de données complet json . Pour mon exemple, j’affiche Crée un arbre de catégorie et du fil d'Ariane, mon dieu! tant de requêtes à faire! Apache lui-même parti! et, en fait, pour ce petit site Web, j’utilise un php qui génère des arbres et du fil d’ariane, l’extraction des données se fait par le module de recherche (qui utilise uniquement l’index), la table de données n’est utilisée que pour la mise à jour ..__ Si je le souhaite, je peux détruire tous les index et les régénérer avec chaque donnée, et effectuer le travail inverse pour, par exemple, détruire toutes les données (json) et ne le régénérer qu’avec la table d’index. Mon projet est jeune, fonctionnant sous php et mysql, mais j’ai parfois recours aux nœuds js et mongodb sera plus efficace pour ce projet.

Utilisez json si vous pensez pouvoir le faire, juste pour le faire, car vous le pouvez! et, oubliez ça si c'était une erreur; essayez de faire le bon ou le mauvais choix, mais essayez!

Faible

un utilisateur français

1
low

Je pense que le stockage de JSON dans une base de données mysql va à l’encontre du but d’utiliser le SGBDR tel qu’il est destiné à l’être. Je ne l'emploierais pas dans des données susceptibles d'être manipulées ou faisant l'objet de rapports, car cela ajoute non seulement de la complexité, mais peut aussi facilement influer sur les performances en fonction de l'utilisation qui en est faite.

Cependant, j'étais curieux de savoir si quelqu'un d'autre pensait à une raison possible de le faire. Je pensais faire une exception à des fins de journalisation. Dans mon cas, je souhaite consigner les demandes comportant un nombre variable de paramètres et d’erreurs. Dans ce cas, je souhaite utiliser des tables pour le type de demandes et les demandes elles-mêmes avec une chaîne JSON de différentes valeurs obtenues.

Dans la situation ci-dessus, les demandes sont consignées et jamais manipulées ou indexées dans le champ Chaîne JSON. CEPENDANT, dans un environnement plus complexe, j'essaierais probablement d'utiliser quelque chose qui a plus une intention pour ce type de données et de le stocker avec ce système. Comme d'autres l'ont déjà dit, cela dépend vraiment de ce que vous essayez d'accomplir, mais le respect des normes contribue toujours à la longévité et à la fiabilité!

1
Mark