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 数据库结构的主要内容,如果未能解决你的问题,请参考以下文章