Facebook 类型社交网络的 NoSQL 数据库结构

Posted

技术标签:

【中文标题】Facebook 类型社交网络的 NoSQL 数据库结构【英文标题】:NoSQL Database Structure for Facebook type social network 【发布时间】:2019-02-26 12:32:32 【问题描述】:

对于 Facebook 类型的社交网络应用程序,需要高性能的数据库结构,以便将数据存储在 Firebase(Cloud Firestore) (NoSQL) 中。

要存储的数据:

 - Userinfo (name, email etc)
 - Friends
 - Posts
 - Comments on posts.

关于查询性能(如果数据库变得庞大),我对以下两种数据库结构感到困惑。

(参考:C_xxx 是 Collection,D_xxx 是文档)

结构1

C_AllData
    - D_UserID-1
        name: xxxx,
        email: yyy,
        friends: [UserID-3, UserID-4]
        - C_Posts
            - D_PostId-1
                Text: hhh
                Date: zzz
                - C_Comments
                    - D_CommentId-1
                        UserID: 3
                        Text: kkk
                    - D_CommentId-2
                        UserID: 4
                        Text: kkk
            - D_PostId-2
                Text: hhh
                Date: zzz
                - C_Comments
                    - D_CommentId-3
                        UserID: 3
                        Text: kkk
                    - D_CommentId-4
                        UserID: 4
                        Text: kkk
    - D_UserID-2
        name: xxxx,
        email: yyy
        friends: [UserID-5, UserID-7]
        - C_Posts
            - D_PostId-3
                Text: hhh
                Date: zzz
                - C_Comments
                    - D_CommentId-5
                        UserID: 5
                        Text: kkk
                    - D_CommentId-6
                        UserID: 7
                        Text: kkk

结构2

C_AllUsers 
    - D_UserID-1
        name: xxxx,
        email: yyy
        friends: [UserID-3, UserID-4]
    - D_UserID-2
        name: xxxx,
        email: yyy
        friends: [UserID-5, UserID-7]

C_AllPosts
    - D_PostId-1
        UserID: 1
        Text: hhh
        Date: zzz
        - C_Comments
            - D_CommentId-1
                UserID: 3
                Text: kkk
            - D_CommentId-2
                UserID: 4
                Text: kkk
    - D_PostId-3
        UserID: 2
        Text: hhh
        Date: zzz
        - C_Comments
            - D_CommentId-5
                UserID: 5
                Text: kkk
            - D_CommentId-6
                UserID: 7
                Text: kkk

我的问题是这两种方法的优缺点是什么?

我能想到的几点如下,如果我错了,请纠正我。

结构 1:

获取给定用户的所有帖子,在结构 1 中更快吗?因为我们要精确定位到确切的集合( AllData/UserID/Posts/ )

由于整个数据库都在一个集合之下,扩展性不好吗?

结构 2:

分区数据库 -> 更好的可扩展性?

划分 DB -> 更好的性能?

更少的嵌套 -> 更好的性能?

一个集合下的AllPosts -> 查询慢?


或者如果你能推荐一个更好的模型,那也很棒。

【问题讨论】:

嘿,到底什么最适合你?你介意发布数据结构吗?这将非常有帮助。 【参考方案1】:

在 Firebase 中,经验法则是将单独的实体类型保存在单独的分支中。这一点尤其重要,因为:

(注意:这里的firebase是firebase实时数据库)

    Firebase 始终加载完整的节点,并且 一旦您授予用户对某个节点的读取权限,他们就可以访问该节点下的所有数据。

例如,在您的第一个数据结构中,要加载朋友列表,您必须加载所有朋友的所有帖子,以及所有这些帖子上的所有 cmets。如果您只想显示朋友姓名列表,那么这比严格需要的数据要多得多。

在您的第二个数据结构中,您离您更近了一步。现在你可以先加载朋友的名字,然后加载他们的帖子。

但即使在这种结构中,您也会遇到同样的问题。如果您想显示一个朋友(或所有朋友)的帖子标题列表,您将不得不加载整个帖子和所有 cmets。这再次比显示帖子标题列表所需的数据多得多。因此,您肯定也希望将 cmets 存储在单独的***列表中,使用帖子的相同键来识别和分组它们。

C_AllPosts
    - D_PostId-1
        UserID: 1
        Text: hhh
        Date: zzz
    - D_PostId-3
        UserID: 2
        Text: hhh
        Date: zzz
C_AllComments
    - D_PostId-1
        - D_CommentId-1
            UserID: 3
            Text: kkk
        - D_CommentId-2
            UserID: 4
            Text: kkk
    - D_PostId-3
        - D_CommentId-5
            UserID: 5
            Text: kkk
        - D_CommentId-6
            UserID: 7
            Text: kkk

现在,如果您想显示帖子及其 cmets,则必须读取两个节点。如果您对多个帖子执行此操作,您最终将获得大量读取,以基本上执行与 SQL JOIN 等效的 NoSQL。这是很正常的,它本质上是一个客户端连接,它并没有你想象的那么慢,因为Firebase pipelines the requests。

关于这类数据建模的更多介绍,我推荐:

这篇文章在NoSQL data modeling Firebase 博文Denormalization is normal 这个视频系列Firebase for SQL developers

这些对之前问题的回答:

Many to Many relationship in Firebase How would you model a collection of users and friends in Firebase? Firebase data structure and url https://***.com/questions/16421179/whats-the-best-way-of-structuring-data-on-firebase/16423051?s=2|19.0394#16423051 https://***.com/questions/30693785/how-to-write-denormalized-data-in-firebase/30699277?s=3|18.5624#30699277 https://***.com/questions/43830610/how-to-denormalize-normalize-data-structure-for-firebase-realtime-database/43832677?s=5|16.2022#43832677

【讨论】:

非常感谢您抽出宝贵时间给出详细的答复。现在我对 Firebase 和 DB 结构有了更好的了解。 弗兰克,你提到 Firebase 总是加载整个节点,但是这篇文章 (***.com/questions/46875966/…),它说 firebase 不加载子集合!所以在我的问题中,在结构 1 中,如果我阅读 /C_AllData/ 它不会在 C_Posts 下给我任何东西,因为它是一个子集合,我需要再次查询它。那么firebase是否加载整个节点? 另外,当我在我的问题中说“Firebase”时,我想说的是 Firebase Cloud Firestore,而不是 Realtime DB。这两者之间的数据结构方法不同? 嘿,kernelman。我的回答确实是基于实时数据库,我一定忽略了 Firestore 标签并提到了集合。对困惑感到抱歉。虽然许多相同的原则适用于 Cloud Firestore,但存在一些关键差异。子集合的自动加载是较大的之一。在这种情况下,将所有 cmets 移动到单个集合中的原因是您有一个用例来查询所有帖子上的 cmets。由于 Firestore(尚)不支持跨多个集合进行查询,因此此用例需要将所有 cmets 放在一个集合中 虽然没有性能差异。 Firestore 的性能保证之一是集合的大小不会影响针对该集合的查询性能。

以上是关于Facebook 类型社交网络的 NoSQL 数据库结构的主要内容,如果未能解决你的问题,请参考以下文章

《NoSQL》服务器缓存

用户操作,如社交网络 facebook、myspace,所有大的

关于 Facebook 等社交网络的数据库模式

带你深入高性能的Nosql数据库:Redis

社交整合平台(facebook、twitter、openid)ids的数据类型都有哪些?

对比云端NoSQL数据库类型