将大量文档写入Firestore的最快方法是什么?


Answers:


26

TL; DR:在Firestore上执行批量日期创建的最快方法是执行并行的单独写入操作。

向Firestore写入1,000个文档需要:

  1. ~105.4s 使用顺序的单个写操作时
  2. ~ 2.8s 使用(2)批处理写操作时
  3. ~ 1.5s 使用并行的单个写操作时

在Firestore上执行大量写入操作的常见方式有三种。

  1. 按顺序执行每个单独的写操作。
  2. 使用批处理写操作。
  3. 并行执行单个写操作。

我们将在下面使用随机文档数据数组依次调查每个数据。


个别顺序写入操作

这是最简单的解决方案:

async function testSequentialIndividualWrites(datas) {
  while (datas.length) {
    await collection.add(datas.shift());
  }
}

我们依次编写每个文档,直到编写完每个文档。然后,我们等待每个写操作完成,然后再开始下一个操作。

用这种方法写1,000个文档大约需要105秒,因此吞吐量大约是每秒10个文档写入


使用批量写入操作

这是最复杂的解决方案。

async function testBatchedWrites(datas) {
  let batch = admin.firestore().batch();
  let count = 0;
  while (datas.length) {
    batch.set(collection.doc(Math.random().toString(36).substring(2, 15)), datas.shift());
    if (++count >= 500 || !datas.length) {
      await batch.commit();
      batch = admin.firestore().batch();
      count = 0;
    }
  }
}

您可以看到我们BatchedWrite通过调用来创建一个对象batch(),填充该对象直到其最大容量为500个文档,然后将其写入Firestore。我们给每个文档一个生成的名称,该名称相对来说可能是唯一的(对于此测试而言足够好)。

用这种方法写1,000个文档大约需要2.8秒,因此吞吐量大约是每秒357个文档写入

这比顺序进行单个写入要快得多。实际上:许多开发人员之所以使用这种方法是因为他们认为这是最快的方法,但是上面的结果已经表明这是不正确的。由于批次的大小限制,代码是迄今为止最复杂的代码。


并行的个别写入操作

Firestore文档说明了有关添加大量数据性能

对于批量数据输入,请使用具有并行写操作的服务器客户端库。批处理写入的性能要好于串行写入,但不优于并行写入。

我们可以使用以下代码对此进行测试:

async function testParallelIndividualWrites(datas) {
  await Promise.all(datas.map((data) => collection.add(data)));
}

此代码以最快的add速度启动操作,然后用于Promise.all()等待操作全部完成。使用这种方法,操作可以并行运行。

使用这种方法写入1,000个文档大约需要1.5秒,因此吞吐量约为每秒667个文档写入

两者的区别不如前两种方法大,但仍比批量写入快1.8倍以上。


一些注意事项:

  • 您可以在Github上找到该测试的完整代码。
  • 在使用Node.js完成测试的同时,您可能会在Admin SDK支持的所有平台上获得相似的结果。
  • 不过,请勿使用客户端SDK执行批量插入,因为结果可能会大不相同且难以预测。
  • 像往常一样,实际性能取决于您的计算机,Internet连接的带宽和延迟以及许多其他因素。基于这些,尽管我希望顺序保持不变,但您可能也会看到差异。
  • 如果您自己的测试中有异常值,或发现完全不同的结果,请在下面留下评论。
  • 批量写入是原子的。因此,如果您在文档之间有依赖关系,并且必须编写所有文档,或者都不写任何文档,则应使用批处理写入。

1
这非常有趣,谢谢您的工作!OOC,您是否测试过并行运行批处理写入?显然,在这种情况下,您将需要更加确定避免两个批次中都有任何文档。
robsiemb

1
我本来打算测试并行批处理写入,但是用完了配额(这是一个免费项目,而且我懒得升级)。今天又是一天,所以我可以尝试一下,如果有意义的话,请更新我的答案。
Frank van Puffelen

2
@robsiemb我也使用并行批处理写入进行了测试。性能与单个并行写入非常相似,因此我会说它们在我的测试中并列第一。我确实希望批处理写入可能会由于后端处理的性质而更快地恶化。结合更复杂的代码,我仍然建议仅将它们用于原子性,而不建议使用感知到但不存在的性能优势。
Frank van Puffelen

如果我“设置”文档而不是“添加”文档,@ FrankvanPuffelen并行化的写操作也会更快吗?我的意思是db.collection('cities')。doc('LA')。set(data)而不是db.collection('cities')。add(data)
alek6dj

调用add()只不过是生成唯一的ID(纯粹是客户端),然后进行set()操作。因此结果应该是相同的。如果那不是您所观察到的,请以最小的情况发布一个新问题,以重现您的尝试。
Frank van Puffelen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.