Utiliser MongoDB et PostgreSQL ensemble


25

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 à tous ceux qui sont confrontés à une décision sur SQL vs NoSQL vs both.

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 la 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 réussissent à être écrites 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 versions de Django pour utiliser la fourche django-nonrel. Il est préférable de vider entièrement l'ORM que de revenir à 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écouper 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 documents

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. Utilisez 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 si nouvelle), 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 que je me sentirais mal à l'aise de jeter toutes mes belles données 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 Django ORM et de l'authentification intégrée et de la gestion des sessions.
  • 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. Il semble qu'ils soient assez recommandés aux personnes qui recherchent des solutions NOSQL, mais je ne vois pas beaucoup de preuves qu'elles soient choisies. 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 battrons 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 seule collection de caractères Documentet appelez-la un jour. Apportez é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 Documentet 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 par la fenêtre du tronc Django. Freebies qui sortent de la fenêtre avec elle: 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, mais 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 se référant à 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éluge 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. Le documentstableau 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 qu'elle fonctionne exactement 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 gardons les batteries que Django nous a données en ce qui concerne les utilisateurs, les sessions, etc.
  • Vous n'avez besoin que d'un seul documentstableau, 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 les 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 garantir l'atomicité, mais garantir l'atomicité de l'é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.

J'irais pour une colonne avec un JSONtype de données. N'ayez pas peur d'utiliser de nouvelles fonctionnalités dans Postgres - l'équipe Postgres ne publie pas de fonctionnalités qui ne sont pas stables. Et 9.2 n'est pas si nouveau en fait). De plus, vous pouvez utiliser les nouvelles fonctionnalités JSON de la version 9.3 une fois qu'elles sont là. Si vous traitez toujours entièrement les documents dans votre code d'application (plutôt que d'utiliser SQL), vous pouvez également stocker JSON dans une textcolonne régulière .
a_horse_with_no_name

Aux répondeurs potentiels: n'hésitez pas à fournir une réponse! Comme cette question a survécu assez longtemps sans réponse "parfaite", j'ai l'intention de répondre à la question avec un post-mortem complet de l'expérience une fois que nous aurons mis en œuvre et passé à la production. Cela pourrait prendre un an dans le futur, mais ne vous inquiétez pas - OP livrera. J'espère que c'est ce que ceux qui ont favorisé / voté pour cette question particulière trouveraient le plus utile: vérification que cela fonctionne ou une explication de quels barrages routiers ont tué l'option côte à côte.
chucksmash

2
@chucksmash. Êtes-vous allé avec # 5, après tout? Comment avez-vous réussi à implémenter les deux dbs? Quels outils avez-vous utilisés? Si non, pourquoi?
xpanta

@chucksmash Toujours en attente des commentaires que vous avez promis.
Bhashit Parikh

@chucksmash OP n'a pas livré ... :(
Albert Rothman

Réponses:


13

Quelques idées....

Généralement, on ne veut pas stocker des informations étroitement liées 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 grand-chose, 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. jsonest 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 TRANSACTIONet si cela réussit, faites vos écritures atomiques dans Mongo. Si cela réussit, vous pouvez le faire COMMITdans PostgreSQL.


1
Ce sont toutes des suggestions géniales. J'avais déjà mentionné l'utilisation de hstore / json (et j'avais réduit silencieusement le xml, parce que, eh bien, le xml) mais je n'avais pas pensé à les utiliser de la manière que vous recommandez. En plus de tout cela, la suggestion de validation de la phase Postgres 2 est d'or. Je n'avais aucune idée que cela existait. Merci pour les super propositions.
chucksmash

L'engagement en deux phases est vraiment de l'or. Cela rend l'utilisation d'un NoSQL en tandem très faisable. Surtout si les données entre les deux bases de données ne sont que rarement liées, et qu'elles résolvent principalement des problèmes différents
haknick

0

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 d'exécuter respectivement "SQL sur n'importe quoi" et "joindre n'importe quoi".

Pour tester Presto, vous pouvez déployer un petit cluster sur AWS EMR avec Hadoop, Hive et Presto (ajouter une teinte si vous ne souhaitez pas utiliser la ligne de commande), cela fonctionne à partir de la boîte - assurez-vous de suivre ces instructions pour configurer les connecteurs . Hive n'est pas strictement nécessaire, mais avec lui, vous pouvez créer des tableaux 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 existe également quelques moyens simples de le déployer sur AWS, Azure ou sur site. Ils ont des cours en ligne sur leur site Web , avec accès à un "laboratoire virtuel" que vous pouvez utiliser pour suivre les cours gratuitement.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.