Firebase Android:使用许多侦听器的慢"join",似乎与文档相矛盾



实现具有多对多关系的Android+Firebase应用:用户<->小部件(小部件可以共享给多个用户)。

考虑:

  1. 列出用户拥有的所有小部件。
  2. 用户只能看到共享给他/她的小部件。
  3. 能够查看共享给定小部件的所有用户。
  4. 单个 Widget 可以由具有相同权限的多个用户拥有/管理(修改 Widget 并更改其共享对象)。类似于Google云端硬盘与特定用户共享的方式。

实现获取(连接样式)的方法之一是遵循以下建议:https://www.firebase.com/docs/android/guide/structuring-data.html(" Joining Flattened Data "):

// fetch a list of Mary's groups
ref.child("users/mchen/groups").addChildEventListener(new ChildEventListener() {
  @Override
  public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
    // for each group, fetch the name and print it
    String groupKey = snapshot.getKey();
    ref.child("groups/" + groupKey + "/name").addListenerForSingleValueEvent(new ValueEventListener() {
      @Override
      public void onDataChange(DataSnapshot snapshot) {
        System.out.println("Mary is a member of this group: " + snapshot.getValue());
      }
      @Override
      public void onCancelled(FirebaseError firebaseError) {
        // ignore
      }
    });
  }
});

这就提出了一个问题,即拥有潜在的许多听众是否会对性能产生负面影响,或者可能会达到一些硬性限制。

但我们在文档中得到了保证:

单独查找每条记录真的可以吗?是的。Firebase 协议使用 Web 套接字,客户端库对传入和传出请求进行了大量内部优化。在我们进入数以万计的记录之前,这种方法是完全合理的。事实上,下载数据所需的时间(即字节计数)超过了有关连接开销的任何其他问题。

但是,可以肯定的是,我制作了一个比较 2 种方法的小测试应用程序:

  1. 许多ValueEventListener-s逐个附加到所有小部件(根据上面提到的Firebase的"结构化数据"指南)
  2. 将单个ChildEventListener附加到托管所有小部件的节点(需要在一个节点下充分构建用户的小部件)

在 4 种不同的设备和安卓版本 (4.x - 5.x) 上进行了测试。火力基地库:'com.firebase:firebase-client-android:2.3.1' .
在第一种方法中,表现相当令人失望。我一直看到 ~15-100 个事件/秒。最低性能,~15 个事件/秒经常出现,所以看起来应该认真对待。在这种情况下,如果用户有 100 个小部件,则需要 ~6 秒才能获取有关所有小部件的信息(例如滚动列表)。这太慢了。对于 1000 个小部件,不同的听众通常需要长达 40 秒的时间才能获取它们的信息。太慢了。

在第二种方法中,我观察到 200-3000 个事件/秒。因此比第一种方法快 15-30 倍!
因此,鉴于Firebase文档[...] Until we get into tens of thousands of records, this approach is perfectly reasonable [...]的工作速度,看起来它的保证并不准确。

鉴于所有这些,我有 4 个相互关联的问题。

  1. 任何人都可以根据自己的经验/基准确认/反驳我的发现吗?有关其他平台的信息也欢迎,因为有计划在多个平台上开发此应用程序。
  2. 性能差异如此巨大的原因可能是什么?也许是内部数据结构?
  3. 有没有办法在保持第一个(多听众)方法的同时提高性能?
  4. 是否应该完全放弃多侦听器方法,转而采用Firebase + Udacity教程中介绍的非规范化多副本方法(https://github.com/udacity/ShoppingListPlusPlus 在"userLists"节点中 - 他们在其中保留购物清单信息的每用户副本)?我在另一个问题中询问了这种方法的含义 - Firebase:通过每用户副本构建数据?数据损坏的风险?
  5. .

欢迎任何其他提示/注意事项。蒂亚。

"This prompts the question whether having potentially many listeners will have a negative impact on performance or perhaps would hit some hard limit."

Firebase Realtime database的答案与新Cloud Firestore database的答案相同。

不管你有多少连接或你有多少监听器,重要的是你在客户端处理了多少数据。

因此,如果你有 100 个侦听器,监听

100 位小数据,那就太便宜了,但如果每个监听器都在监听不断变化的数据流,那么客户端处理它的成本就会非常高。

而且因为移动设备差别很大,所以很难知道多少是太多。因此,如果你的目标是那些往往拥有非常高端手机的美国用户,如果我们瞄准那些手机电量低得多的国家,那将是一个不同的限制。

因此,您可以

根据需要拥有任意数量的侦听器,如果您根据活动的生命周期删除它们,如此处所示。

还有另一种方法,使用 addListenerForSingleValueEvent .在这种情况下,无需删除侦听器。

最新更新