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 Document
et 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
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 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 documents
tableau 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
documents
tableau, 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.
JSON
type 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 unetext
colonne régulière .