web-dev-qa-db-fra.com

Utiliser MongoDB et PostgreSQL ensemble

Mon projet actuel consiste essentiellement à exécuter le système de gestion des documents de l'usine.

Cela dit, il y a des rides (surprise, surprise). Bien que certaines rides soient assez spécifiques au projet, je pense qu'il y a des observations générales et des questions qui n'ont pas eu de réponse canonique (que je pourrais trouver, de toute façon) et qui sont applicables à un domaine de problème plus large . Il y en a beaucoup ici et je ne suis pas sûr que cela corresponde bien au format StackExchange Q&A, mais je pense que c'est a) une question à laquelle il est possible de répondre et b) suffisamment non spécifique pour que cela puisse bénéficier à la communauté. Certaines de mes considérations me sont spécifiques, mais je pense que la question pourrait être utile à quiconque confronté à la décision de SQL vs NoSQL vs les deux.

L'arrière-plan:

L'application Web que nous construisons contient des données de nature clairement relationnelle ainsi que des données orientées document. Nous aimerions avoir notre gâteau et le manger aussi.

TL; DR: Je pense que le numéro 5 ci-dessous réussit le test de l'odorat. Le faites vous? Quelqu'un a-t-il de l'expérience avec une telle intégration de SQL et NOSQL dans une seule application? J'ai essayé de lister toutes les approches possibles de cette classe de problèmes ci-dessous. Ai-je manqué une alternative prometteuse?

Complexités:

  • Il existe de nombreuses classes de documents différentes. Les exigences exigent déjà des dizaines de documents différents. Ce nombre ne fera qu'augmenter. Le meilleur cas possible serait celui dans lequel nous pourrions tirer parti d'un langage spécifique à un domaine simple, de la génération de code et d'un schéma flexible afin que les experts du domaine puissent gérer l'ajout de nouvelles classes de documents sans l'intervention de DBA ou de programmeurs. (Remarque: déjà conscient que nous vivons Dixième règle de Greenspun )
  • L'intégrité des précédentes écritures réussies est une exigence centrale du projet. Les données seront critiques pour l'entreprise. La sémantique ACID complète sur les écritures peut être sacrifiée à condition que les choses qui sont écrites avec succès restent écrites.
  • Les documents sont eux-mêmes complexes. Le prototype de document dans notre cas spécifique nécessitera le stockage de plus de 150 éléments distincts de données par instance de document. Le cas pathologique pourrait être d'un ordre de grandeur pire, mais certainement pas deux.
  • Une seule classe de documents est une cible mobile sujette à des mises à jour ultérieures.
  • Nous aimons les trucs gratuits que nous obtenons de Django lorsque nous le connectons à une base de données relationnelle. Nous aimerions garder les cadeaux sans avoir à reculer de deux Django versions pour utiliser la fourche Django-nonrel. Le vidage complet de l'ORM est préférable à la rétrogradation en 1.3.

Essentiellement, il s'agit d'un méli-mélo de données relationnelles (vos applications Web typiques comme les utilisateurs, les groupes, etc., ainsi que les métadonnées de document que nous devrons être en mesure de découper et de dés avec des requêtes complexes en temps réel) et de données de document (par exemple les centaines de champs que nous n'avons aucun intérêt à joindre ou à interroger - notre seul cas d'utilisation pour les données sera d'afficher le document unique dans lequel elles ont été saisies).

Je voulais faire un contrôle de santé mentale (si vous vérifiez mon historique de publication, je suis assez explicite sur le fait que je ne suis pas un DBA) sur ma méthode préférée ainsi que d'énumérer toutes les options que j'ai rencontrées pour que d'autres résolvent des problèmes globalement similaires impliquant à la fois des données relationnelles et non relationnelles.

Solutions proposées:

1. Une table par classe de document

Chaque classe de document obtient sa propre table, avec des colonnes pour toutes les métadonnées et données.

Avantages:

  • Le modèle de données SQL standard est en jeu.
  • Les données relationnelles sont traitées de la meilleure façon possible. Nous dénormaliserons plus tard si nous en avons besoin.
  • L'interface d'administration intégrée de Django est à l'aise avec l'introspection de ces tables et l'ORM peut vivre heureux avec 100% des données prêtes à l'emploi.

Désavantages:

  • Cauchemar d'entretien. Des dizaines (centaines?) De tables avec (dizaines de?) Milliers de colonnes.
  • Logique au niveau de l'application chargée de décider exactement à quelle table écrire. Faire du nom de table un paramètre pour une requête pue.
  • Fondamentalement, toutes les modifications de la logique métier nécessiteront des modifications de schéma.
  • Les cas pathologiques peuvent nécessiter l'entrelacement des données pour des formulaires uniques sur plusieurs tables (voir: Quel est le nombre maximal de colonnes dans une table PostgreSQL? ).
  • Nous aurions probablement besoin d'aller trouver un vrai DBA honnête à Dieu qui finirait sans aucun doute par haïr la vie et nous.

2. Modélisation EAV

Il y a juste une table des champs. La modélisation Entité-Attribut-Valeur est déjà bien comprise. Je l'ai inclus pour être complet. Je ne pense pas qu'un nouveau projet démarré en 2013 irait volontairement avec une approche EAV.

Avantages:

  • Facile à modéliser.

Désavantages:

  • Plus difficile à interroger.
  • La couche DB n'a plus de représentation directe de ce qui constitue un objet de niveau application.
  • Nous perdrions la vérification des contraintes au niveau DB.
  • Le nombre de lignes sur une table augmentera de 100 à 1000 fois plus rapidement. Point de douleur futur probable, en termes de performances.
  • Indexation limitée possible.
  • Le schéma DB est absurde en ce qui concerne ORM. Les batteries incluses dans l'application Web sont préservées, mais les modèles de données personnalisés vont nécessiter des requêtes personnalisées.

3. Utiliser les champs hstore ou json de PostgreSQL

L'un ou l'autre de ces types de champ ferait l'affaire pour stocker des données sans schéma dans le contexte d'une base de données relationnelle. La seule raison pour laquelle je ne saute pas immédiatement à cette solution est qu'elle est relativement nouvelle (introduite dans la version 8.4 donc pas ça nouveau), je n'ai aucune exposition précédente à elle et je me méfie. Cela me semble erroné précisément pour les mêmes raisons pour lesquelles je serais mal à l'aise de jeter toutes mes données Nice, facilement normalisées dans Mongo - même si Mongo peut gérer les références entre les documents.

Avantages:

  • Nous bénéficions des avantages de l'ORM Django et de l'authentification et de la gestion de session intégrées.
  • Tout reste dans un seul backend que nous avons déjà utilisé avec succès sur d'autres projets.

Désavantages:

  • Aucune expérience avec cela, personnellement.
  • Cela ne ressemble pas à une fonctionnalité très utilisée. On dirait qu'ils sont recommandés un peu aux gens qui cherchent des solutions NOSQL mais je ne vois pas beaucoup de preuves qu'ils sont choisis. Cela me fait penser que je dois manquer quelque chose.
  • Toutes les valeurs stockées sont des chaînes. Perdre la vérification des contraintes de niveau DB.
  • Les données de l'hstore ne seront jamais affichées pour l'utilisateur à moins qu'il ne visualise spécifiquement un document, mais les métadonnées stockées dans des colonnes plus standard le seront. Nous allons battre ces métadonnées et je crains que les magasins de grande taille que nous allons créer ne présentent des inconvénients de performances.

4. Passez au document intégral

Créez tous les documents (au sens MongoDB). Créez une collection unique de type Document et appelez-la un jour. Importez également toutes les données périphériques (y compris les données sur les comptes d'utilisateurs, les groupes, etc.) dans Mongo. Cette solution est évidemment meilleure que la modélisation EAV mais cela me semble mal pour la même raison # 3 se sentait mal - ils ont tous les deux envie d'utiliser votre marteau comme tournevis aussi.

Avantages:

  • Pas besoin de modéliser les données à l'avance. Ayez une collection avec des documents de type Document et appelez-la un jour.
  • Bonnes caractéristiques de mise à l'échelle connues, si la collection doit évoluer pour englober des millions voire des milliards de documents.
  • Le format JSON (BSON) est intuitif pour les développeurs.
  • Si je comprends bien (ce qui n'est que vaguement à ce stade), en étant paranoïaque en ce qui concerne le niveau de préoccupation en écriture, même une seule instance peut fournir une sécurité des données assez solide en cas de tout et n'importe quoi jusqu'à une panne de disque dur.

Désavantages:

  • L'ORM est hors de la fenêtre pour Django trunk. Freebies qui sortent de la fenêtre avec lui: le cadre d'authentification, le cadre de sessions, l'interface d'administration, sûrement beaucoup d'autres choses.
  • Doit utiliser les capacités de référencement de mongo (qui nécessitent plusieurs requêtes) ou dénormaliser les données. Non seulement nous perdons des cadeaux que nous avons obtenus de Django, nous perdons également des cadeaux comme les JOIN que nous tenions pour acquis dans PostgreSQL.
  • Sécurité des données. Quand on lit sur MongoDB, il semble qu'il y ait toujours au moins une personne qui se réfère à la façon dont il va monter et perdre vos données. Ils ne citent jamais un événement particulier et il se peut que tout cela soit juste un délabré ou simplement lié à l'ancien incendie par défaut et oublie le problème d'écriture, mais cela m'inquiète toujours. Nous utiliserons bien sûr une stratégie de sauvegarde assez paranoïaque dans tous les cas (si les données sont corrompues silencieusement cela pourrait bien être immatériel bien sûr ..).

5. PostgreSQL et MongoDB

Les données relationnelles vont dans la base de données relationnelle et les données de document vont dans la base de données orientée document. La table documents de la base de données relationnelle contient toutes les données dont nous pourrions avoir besoin pour indexer ou découper et découper ainsi qu'un MongoDB ObjectId que nous utiliserions lorsque nous aurons besoin de rechercher les valeurs réelles des champs sur les documents. Nous ne serions pas en mesure d'utiliser l'ORM ou l'administrateur intégré pour les valeurs des documents eux-mêmes, mais ce n'est pas une grosse perte puisque l'application entière est essentiellement une interface d'administration pour les documents et nous aurions probablement dû personnaliser cette partie spécifique de l'ORM à un degré inacceptable pour le faire fonctionner comme nous en avons besoin.

Avantages:

  • Chaque backend ne fait que ce pour quoi il est bon.
  • Les références entre les modèles sont conservées sans nécessiter plusieurs requêtes.
  • Nous arrivons à garder les batteries Django nous a donné en ce qui concerne les utilisateurs, les sessions, etc.).
  • Vous n'avez besoin que d'une seule table documents, quel que soit le nombre de classes de documents créées.
  • Les données de document les moins souvent interrogées sont fortement séparées des métadonnées beaucoup plus souvent interrogées.

Désavantages:

  • La récupération des données du document nécessitera 2 requêtes séquentielles, d'abord contre la base de données SQL puis contre la MongoDB (bien que ce ne soit pas pire que si les mêmes données avaient été stockées dans Mongo et non dénormalisées)
  • L'écriture ne sera plus atomique. Une écriture sur un seul document Mongo est garantie d'être atomique et PG peut évidemment faire des garanties d'atomicité, mais garantir l'atomicité d'écriture sur les deux nécessitera une logique d'application, sans doute avec une pénalité de performance et de complexité.
  • Deux backends = deux langages de requête = deux programmes différents avec des exigences administratives différentes = deux bases de données en lice pour la mémoire.
25
chucksmash

Quelques idées....

Généralement, on ne veut pas stocker des éléments d'informations étroitement liés dans différents systèmes. Les chances que les choses ne se synchronisent pas sont importantes et maintenant, au lieu d'un problème, vous en avez deux. Une chose que vous pouvez faire avec Mongo est de l'utiliser pour acheminer ou sortir vos données. Ma préférence est de tout garder dans PostgreSQL dans la mesure du possible. Cependant, je noterais que cela nécessite vraiment une connaissance approfondie de la programmation PostgreSQL et n'est pas destiné aux magasins qui ne souhaitent pas se consacrer à l'utilisation de fonctionnalités avancées. Je vois un ensemble d'options quelque peu différent du vôtre. Comme ma préférence n'est pas quelque chose que je vois dans la liste, je vous la donnerai.

Vous pouvez probablement séparer vos métadonnées en données communes, données requises pour les classes et données de document. À cet égard, vous auriez un tableau de catalogue général avec les informations communes de base plus un tableau par classe. Dans ce tableau, vous auriez un champ hstore, json ou xml qui stockerait le reste des données ainsi que des colonnes où vous stockez des données qui doivent être contraintes de manière significative. Cela réduirait ce que vous devez mettre dans ces tables par classe, mais vous permettrait de tirer parti des contraintes comme vous le souhaitez. Les trois options ont des problèmes différents et méritent d'être examinées séparément:

hstore est relativement limité mais aussi utilisé par beaucoup de gens. Ce n'est pas extrêmement nouveau mais c'est seulement un magasin de clés/valeurs, et est incapable de structures de données imbriquées, contrairement à json et xml.

json est assez nouveau et ne fait pas grand-chose en ce moment. Cela ne signifie pas que vous ne pouvez pas en faire beaucoup, mais vous n'allez pas en faire beaucoup hors de la boîte. Si vous le faites, vous pouvez vous attendre à faire une quantité importante de programmation, probablement dans plv8js ou, si vous voulez vous en tenir à des environnements plus anciens, plperlu ou plpython. json est mieux pris en charge dans 9.3 bien qu'au moins dans les instantanés de développement actuels, donc quand cette version sera publiée, les choses iront mieux.

xml est le meilleur supporté des trois, avec le plus de fonctionnalités et le plus long historique de support. Là encore, c'est XML .....

Cependant, si vous décidez d'aller avec Mongo et PostgreSQL ensemble, notez que PostgreSQL prend en charge la validation en 2 phases, ce qui signifie que vous pouvez exécuter les opérations d'écriture, puis lancez PREPARE TRANSACTION et si cela réussit, faites vos écritures atomiques en Mongo. Si cela réussit, vous pouvez alors COMMIT dans PostgreSQL.

14
Chris Travers

Vous pouvez configurer un moteur de requête tel que Presto ou Dremio pour joindre des données résidant dans MongoDB et Postgres avec une seule requête. Les deux ont des connecteurs pour chacune de ces bases de données (voir les documents ici et ici ) et proposent, respectivement, d'exécuter "SQL sur n'importe quoi" et de "joindre n'importe quoi".

Pour tester Presto, vous pouvez déployer un petit cluster sur AWS EMR avec Hadoop, Hive et Presto (ajoutez une teinte si vous ne souhaitez pas utiliser la ligne de commande), cela fonctionne à partir de la boîte - assurez-vous de suivez ces instructions pour configurer les connecteurs . Hive n'est pas strictement nécessaire, mais avec lui, vous pouvez créer des tables en utilisant le résultat des jointures entre Mongo et Postgres (consultez cette page pour des exemples). Il existe également une version payante sur le marché , qui est (soi-disant) fortement optimisée et dispose d'un essai de 30 jours.

Je n'ai pas utilisé Dremio, mais il y a aussi quelques façons simples de le déployer sur AWS, Azure ou sur site. Ils ont certains cours en ligne sur leur site Web , avec accès à un "laboratoire virtuel" que vous pouvez utiliser pour suivre les cours gratuitement.

0
kadu