web-dev-qa-db-fra.com

Comment suivez-vous les relations d'enregistrement dans NoSQL?

J'essaie de comprendre l'équivalent des clés étrangères et des index dans les bases de données NoSQL KVP ou Document. Puisqu'il n'y a pas de tables pivotantes (pour ajouter des clés marquant une relation entre deux objets), je suis vraiment perplexe quant à la façon dont vous pourriez récupérer des données d'une manière qui serait utile pour les pages Web normales.

Disons que j'ai un utilisateur, et cet utilisateur laisse de nombreux commentaires partout sur le site. La seule façon dont je peux penser pour garder une trace des commentaires des utilisateurs est de

  1. Intégrez-les dans l'objet utilisateur (ce qui semble tout à fait inutile)
  2. Créez et gérez un user_id:comments valeur qui contient une liste de la clé de chaque commentaire [commentaire: 34, commentaire: 197, etc ...] afin que je puisse les récupérer au besoin.

Cependant, en prenant le deuxième exemple, vous toucherez bientôt un mur de briques lorsque vous l'utiliserez pour suivre d'autres choses comme une clé appelée "active_comments" qui pourrait contenir 30 millions d'identifiants, ce qui en fait coûte une tonne pour interroger chaque page juste pour connaître certains commentaires actifs récents. Il serait également très sujet aux conditions de course car de nombreuses pages pourraient essayer de le mettre à jour en même temps.

Comment puis-je suivre des relations comme les suivantes dans une base de données NoSQL?

  • Tous les commentaires d'un utilisateur
  • Tous les commentaires actifs
  • Tous les messages tagués avec [mot clé]
  • Tous les étudiants d'un club - ou tous les clubs dans lesquels un étudiant est

Ou est-ce que je pense mal à cela?

109
Xeoncross

Toutes les réponses sur la façon de stocker des associations plusieurs-à-plusieurs de la "manière NoSQL" se réduisent à la même chose: stockage de données redondant.

Dans NoSQL, vous ne concevez pas votre base de données en fonction des relations entre les entités de données. Vous concevez votre base de données en fonction des requêtes que vous exécuterez sur elle. Utilisez les mêmes critères que vous utiliseriez pour dénormaliser une base de données relationnelle: s'il est plus important que les données aient de la cohésion (pensez aux valeurs dans une liste séparée par des virgules au lieu d'une table normalisée), faites-le de cette façon.

Mais cela optimise inévitablement pour un type de requête (par exemple, les commentaires de n'importe quel utilisateur pour un article donné) au détriment d'autres types de requêtes (commentaires pour tout article par un utilisateur donné). Si votre application a besoin que les deux types de requêtes soient également optimisés, vous ne devez pas dénormaliser. De même, vous ne devez pas utiliser une solution NoSQL si vous devez utiliser les données de manière relationnelle.

La dénormalisation et la redondance présentent un risque de désynchronisation des ensembles de données redondants. Cela s'appelle une anomalie . Lorsque vous utilisez une base de données relationnelle normalisée, le SGBDR peut empêcher les anomalies. Dans une base de données dénormalisée ou dans NoSQL, il devient de votre responsabilité d'écrire du code d'application pour éviter les anomalies.

On pourrait penser que ce serait formidable pour une base de données NoSQL de faire le dur travail de prévention des anomalies pour vous. Il y a un paradigme qui peut le faire - le paradigme relationnel.

160
Bill Karwin

L'approche couchDB suggère d'émettre des classes appropriées de trucs en phase de carte et de le résumer en réduire .. Vous pouvez donc mapper tous les commentaires et émettre 1 pour l'utilisateur donné et en imprimer plus tard seulement. Il faudrait cependant beaucoup de stockage sur disque pour créer des vues persistantes de toutes les données traçables dans couchDB. btw ils ont aussi cette page wiki sur les relations: http://wiki.Apache.org/couchdb/EntityRelationship .

Riak, d'autre part, a un outil pour établir des relations. C'est un lien. Vous pouvez saisir l'adresse d'un document lié (ici commentaire) au document "racine" (ici document utilisateur). Il a une astuce. S'il est distribué, il peut être modifié en même temps à plusieurs endroits. Cela provoquera des conflits et, par conséquent, un énorme arbre d'horloge vectorielle:/..pas si mal, pas si bien.

Riak dispose également d'un autre "mécanisme". Il a un espace de nom de clé à 2 couches, appelé compartiment et clé. Ainsi, par exemple pour les étudiants, si nous avons les clubs A, B et C et les étudiants StudentX, StudentY, vous pouvez maintenir la convention suivante:

{ Key = {ClubA, StudentX}, Value = true }, 
{ Key = {ClubB, StudentX}, Value = true }, 
{ Key = {ClubA, StudentY}, Value = true }

et pour lire la relation, il suffit de lister les clés dans des compartiments donnés. Qu'est-ce qui ne va pas avec ça? C'est sacrément lent. L'inscription des compartiments n'a jamais été une priorité pour riak. Ça va de mieux en mieux. btw. vous ne perdez pas de mémoire car cet exemple {true} peut être lié à un seul profil complet de StudentX ou Y (ici les conflits ne sont pas possibles).

Comme vous le voyez NoSQL! = NoSQL. Vous devez examiner une implémentation spécifique et la tester par vous-même.

Mentionné avant que les magasins Column semblent bien adaptés aux relations .. mais tout dépend de vos besoins A et C et P;) Si vous n'avez pas besoin de A et que vous avez moins de Peta octets, laissez simplement , allez-y avec MySql ou Postgres.

bonne chance

4
user425720
  1. user: userid: comments est une approche raisonnable - considérez-le comme l'équivalent d'un index de colonne dans SQL, avec l'exigence supplémentaire que vous ne pouvez pas interroger sur des colonnes non indexées.

  2. C'est là que vous devez réfléchir à vos besoins. Une liste de 30 millions d'articles n'est pas déraisonnable parce qu'elle est lente, mais parce qu'il est impossible de faire quoi que ce soit avec elle. Si votre véritable besoin est d'afficher des commentaires récents, il vaut mieux garder une liste très courte qui est mise à jour chaque fois qu'un commentaire est ajouté - n'oubliez pas que NoSQL n'a pas d'exigence de normalisation. Les conditions de concurrence sont un problème avec les listes dans un magasin de valeurs de clés de base, mais généralement, votre plate-forme prend correctement en charge les listes, vous pouvez faire quelque chose avec des verrous ou vous ne vous souciez pas réellement des mises à jour qui ont échoué.

  3. Identique aux commentaires des utilisateurs - créez un mot-clé d'index: publications

  4. Plus ou moins la même chose - probablement une liste de clubs en tant que propriété de l'étudiant et un index dans ce domaine pour obtenir tous les membres d'un club

4
Tom Clarkson

Tu as

"user": {
    "userid": "unique value",
    "category": "student",
    "metainfo": "yada yada yada",
    "clubs": ["archery", "kendo"]
}

"comments": {
    "commentid": "unique value",
    "pageid": "unique value",
    "post-time": "ISO Date",
    "userid": "OP id -> THIS IS IMPORTANT"
}

"page": {
    "pageid": "unique value",
    "post-time": "ISO Date",
    "op-id": "user id",
    "tag": ["abc", "zxcv", "qwer"]
}

Eh bien, dans une base de données relationnelle, la chose normale à faire serait dans une relation un-à-plusieurs est de normaliser les données. C'est la même chose que vous feriez dans une base de données NoSQL également. Indexez simplement les champs avec lesquels vous allez chercher les informations.

Par exemple, les index importants pour vous sont

  • Comment.UserID
  • Comment.PageID
  • Comment.PostTime
  • Page.Tag []

Si vous utilisez NosDB (une base de données NoSQL basée sur .NET avec prise en charge SQL) vos requêtes seront comme

 SELECT * FROM Comments WHERE userid = ‘That user’;

 SELECT * FROM Comments WHERE pageid = ‘That user’;

 SELECT * FROM Comments WHERE post-time > DateTime('2016, 1, 1');

 SELECT * FROM Page WHERE tag = 'kendo'

Vérifiez tous les types de requêtes pris en charge dans leur Aide-mémoire SQL ou dans la documentation.

1
Basit Anwer