我试图找出NoSQL KVP或Document数据库中的外键和索引的等价物。由于没有关键表(添加标记两个对象之间关系的键),我真的很难过如何能够以对普通网页有用的方式检索数据。
假设我有一个用户,该用户在整个网站上留下了很多评论。我能想到跟踪用户评论的唯一方法是
user_id:comments
值,其中包含每个注释的键列表[注释:34,注释:197等等],以便我可以根据需要获取它们。然而,采用第二个例子,当你用它来追踪其他东西时,你很快就会碰到一堵砖墙,例如一个名为“active_comments”的密钥,它可能包含3000万个ID,因为它成本为TON 查询每个页面只是为了了解最近的一些活跃评论。它也很容易出现竞争条件,因为很多页面可能会同时尝试更新它。
如何在NoSQL数据库中跟踪以下关系?
或者我是否错误地考虑了这个问题?
答案 0 :(得分:158)
如何以“NoSQL方式”存储多对多关联的所有答案都会减少到同样的效果:冗余地存储数据。
在NoSQL中,您不会根据数据实体之间的关系设计数据库。您可以根据要对其运行的查询来设计数据库。使用与用于非规范化关系数据库相同的标准:如果数据具有内聚性更重要(考虑以逗号分隔的列表而不是规范化表格中的值),那么就这样做。
但是这不可避免地优化了一种类型的查询(例如,任何用户对给定文章的评论),代价是其他类型的查询(给定用户对任何文章的评论)。如果您的应用程序需要同等优化两种类型的查询,则不应该非规范化。同样,如果您需要以关系方式使用数据,则不应使用NoSQL解决方案。
非规范化和冗余存在风险,冗余数据集将彼此不同步。这称为异常。使用规范化关系数据库时,RDBMS可以防止异常。在非规范化数据库或NoSQL中,您有责任编写应用程序代码以防止出现异常。
有人可能会认为,对于NoSQL数据库来说,做一些防止异常的艰苦工作会很棒。有一种范式可以做到这一点 - 关系范式。
答案 1 :(得分:4)
user:userid:comments是一种合理的方法 - 将其视为SQL中列索引的等价物,并增加了对无索引列进行查询的要求。
这是您需要考虑您的要求的地方。一个包含3000万个项目的列表并不是不合理的,因为它很慢,但因为用它做任何事都是不切实际的。如果您真正的要求是显示一些最近的注释,那么最好保留一个非常短的列表,只要添加注释就会更新 - 请记住NoSQL没有规范化要求。竞争条件是基本键值存储中的列表的问题,但通常您的平台正确支持列表,您可以使用锁执行某些操作,或者您实际上并不关心更新失败。
与用户评论相同 - 创建索引关键字:posts
更多相同 - 可能是一个俱乐部列表作为学生的财产,以及该领域的索引,以获得俱乐部的所有成员
答案 2 :(得分:4)
couchDB方法建议在map阶段发出适当类别的东西,并将其汇总为reduce ..因此,您可以映射所有注释并为给定用户发出1
,然后仅打印出来。然而,需要大量磁盘存储来构建couchDB中所有可跟踪数据的持久视图。顺便说一下,他们还有关于人际关系的维基页面:http://wiki.apache.org/couchdb/EntityRelationship。
Riak还有另一个'机制'。它有2层密钥名称空间,所以称为桶和密钥。因此,对于学生的例子,如果我们有俱乐部A,B和C以及学生StudentX,StudentY,您可以遵循以下惯例:
{ Key = {ClubA, StudentX}, Value = true },
{ Key = {ClubB, StudentX}, Value = true },
{ Key = {ClubA, StudentY}, Value = true }
并阅读关系只是给定存储桶中的列表键。那有什么不对吗?这很慢。列表桶从未成为riak的优先事项。越来越好了。顺便说一句。你不浪费内存,因为这个例子{true}
可以链接到StudentX或Y的单个完整配置文件(这里不存在冲突)。
如你所见NoSQL!= NoSQL。您需要查看具体的实现并自行测试。
之前提到列存储看起来非常适合关系..但这一切都取决于你的A和C和P的需要;)如果你不需要A并且你有少于Peta字节就离开它,继续使用MySql或Postgres。
祝你好运答案 3 :(得分:1)
你有
"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"]
}
在关系数据库中,正常的做法是以一对多关系来规范化数据。这与你在NoSQL数据库中所做的一样。只需索引您将获取信息的字段。
例如,您的重要索引是
如果您使用的是NosDB (A .NET based NoSQL Database with SQL support),则您的查询就像
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'
检查其SQL cheat sheet或文档中支持的所有查询类型。
答案 4 :(得分:-1)
尽管,在这种情况下最好使用RDBMS代替NoSQL,但一种可行的解决方案是维护其他节点或集合以管理映射和索引。以额外的集合/节点和处理的形式可能会产生额外的成本,但是它将提供易于维护的解决方案并避免数据冗余。