performance - Firestore 聊天应用 : Is this a valid document structure for multi-recipient messages?

标签 performance firebase indexing google-cloud-firestore

假设一个聊天应用有 1000 万 Firebase 用户和数亿条消息。

我有一个 Firestore 集合,其中包含在时间序列中表示为文档的消息,并且这些消息中的每一个都可能被多达 100 个这些用户接收和查看。请注意,这些用户并没有组织在稳定的组中,因为每条消息可能有完全不同的一组用户来接收它。

我需要能够非常有效地(在时间和成本方面)找到,
某个特定时间后的所有消息,定向到某个特定用户。

我的第一次失败尝试是在 recipients 中列出收件人用户。数组字段,例如:

sender: user3567381
dateTime : 2019-01-24T20:37:28Z
recipients : [user1033029, user9273842, user8293413, user6273581]

但是,这不允许我有效地进行查询。

作为 second failed attempt ,由于 Firestore 是无模式的,我想到了 使每个用户成为一个字段 , 像这样:
sender: user3567381
dateTime : 2019-01-24T20:37:28Z
user1033029 : true
user9273842 : true
user8293413 : true
user6273581 : true

然后,例如,如果我想知道今天下午 3:00 之后用户 8293413 的所有消息,我可以这样做:
messages.where("user8293413", "==", true).where("dateTime", ">=", "2019-01-24T15:00:00Z")

这是一个复合索引查询,每个用户需要一个索引。不幸的是,存在限制 200 composite-indexes每个数据库。

为了解决这个问题,我的 当前尝试 是转日期 进入用户字段的值,如下所示:
sender: user3567381
dateTime : 2019-01-24T20:37:28Z
user1033029 : 2019-01-24T20:37:28Z
user9273842 : 2019-01-24T20:37:28Z
user8293413 : 2019-01-24T20:37:28Z
user6273581 : 2019-01-24T20:37:28Z

现在,如果我想知道今天下午 3:00 之后用户 8293413 的所有消息,我可以这样做:
messages.where("user8293413", ">=", "2019-01-24T15:00:00Z")

请注意,这现在是 单字段索引 .

从文档中我知道 Firestore 将为所有字段创建单字段索引,因此这意味着它将专门为 user8293413 创建索引。
这意味着搜索会很快,对吗?并且读取次数将保持在最低限度(每条消息读取一次)。

但是,由于我有 1000 万用户, Firestore 将不得不创建 1000 万个单字段索引 (假设所有用户都收到消息)整个数据库。

来自 documentation Firestore 有以下限制:
  • 数据库的最大复合索引数: 200
  • 数据库的最大单字段索引豁免数: 200
  • 每个文档的最大索引条目数: 40,000 (对于一个文档,索引条目的数量是以下各项的总和:单字段索引条目的数量+复合索引条目的数量)
  • 索引条目的最大大小: 7.5 KiB
  • 文档索引条目大小的最大总和: 8 MiB (总大小为文档的以下总和:文档的单字段索引条目的大小之和+文档的复合索引条目的大小之和)
  • 索引字段值的最大大小: 1500 字节 (超过 1500 字节的字段值被截断。涉及截断字段值的查询可能返回不一致的结果。)

  • 通过阅读以上内容,这些引起了我的注意:
  • 每个文档的最大索引条目数: 40,000
  • 文档索引条目大小的最大总和:8 MiB

  • 但是,他们声明限制是 ​​每个文档 , 不是针对每个数据库。而且我只有数百万个数据库索引,而不是每个文档。

    那是问题吗?这么多索引会影响性能吗?所有这些索引的存储成本如何? Firebase 是否为每个数据库的大量索引做好了准备?

    最佳答案

    尽管几个月后,对于任何 future 的用户来说,似乎第一次尝试可能效果最好。

    对时间戳使用单个静态字段,对收件人使用单个静态字段意味着索引将保持可忽略不计,您不必考虑它们。

    要查找用户的所有消息,这似乎是您的目标:

    For example, if I want to know all messages for user 8293413 after 3:00 PM today, I could do it like this:



    这在 中看起来就像这样伪代码 :
    firestore.collection('messages').where('recipient', 'array_contains', userId).where('time', '>', '3pm today'.get()
    

    这在性能上应该很容易,Firebase 已针对它提供的运算符进行了优化,例如'==', '>=', 'array_contains'

    关于performance - Firestore 聊天应用 : Is this a valid document structure for multi-recipient messages?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54369877/

    相关文章:

    javascript - 清除 JavaScript 中的事件处理程序有多重要?

    firebase - Auth0 与 Firebase 委派

    javascript - 我无法将我的 Vuejs 应用连接到 Firebase

    sql-server - 索引会提高varchar(max)查询性能吗,以及如何创建索引

    Java 枚举 - 枚举上的 Switch 语句与访问者模式 - 性能优势?

    performance - 在 golang 中,使用 make 与 {} 初始化的 map 之间是否存在任何性能差异

    c++ - 有没有办法在 C++ 中调用基类函数的所有子类?

    java - Android 2.3 无法在未调用 Looper.prepare() (AsyncTask) 的线程内创建处理程序

    MYSQL 更改表 - 添加 INDEX + FOREIGN KEY 给出错误 1005

    非密集索引的数据库查询