node.js - 将大量文档写入 Firestore 的最快方法是什么?
问题描述
我需要将大量文档写入 Firestore。
在 Node.js 中执行此操作的最快方法是什么?
解决方案
TL;DR:在 Firestore 上执行批量日期创建的最快方法是执行并行的单独写入操作。
将 1,000 个文档写入 Firestore 需要:
~105.4s
使用顺序的单独写入操作时~ 2.8s
使用 (2) 批量写入操作时~ 1.5s
使用并行单独写入操作时
在 Firestore 上执行大量写入操作的常用方法有 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 执行批量插入,因为结果可能非常不同并且更难以预测。
- 像往常一样,实际性能取决于您的机器、互联网连接的带宽和延迟以及许多其他因素。基于这些,您也可能会看到差异中的差异,尽管我希望顺序保持不变。
- 如果您在自己的测试中有任何异常值,或者发现完全不同的结果,请在下方发表评论。
- 批量写入是原子的。因此,如果您的文档之间存在依赖关系,并且必须写入所有文档,或者必须不编写任何文档,则应该使用批量写入。
推荐阅读
- reactjs - 无法在 react-native-html-pdf 中加载许多图像
- c# - AspNet-Contrib 仅适用于新项目
- python - 我应该为 numpy 数组添加哪些函数以考虑另一个 numpy 数组是包含单个元素还是多个元素?
- javascript - 检查多个复选框时过滤数据
- reactjs - ReactDOM.render 中的 Index.js 中的 React 无效挂钩调用
- typescript - 我是否错误地拆分了这些构造?
- android - kotlin 中的墙纸管理器中的问题
- ios - 如何在 SwiftUI 中更改状态栏背景颜色?
- java - 有什么办法可以在按下一段时间后在另一个视图之上打开不同的视图
- sql - 我希望根据组合框选择转到下一行 SQL 数据