Preciso escrever um grande número de documentos no Firestore.
Qual é a maneira mais rápida de fazer isso no Node.js?
fonte
Preciso escrever um grande número de documentos no Firestore.
Qual é a maneira mais rápida de fazer isso no Node.js?
TL; DR: A maneira mais rápida de executar a criação de datas em massa no Firestore é executando operações de gravação individuais paralelas.
Escrever 1.000 documentos no Firestore leva:
~105.4s
ao usar operações de gravação individual sequencial~ 2.8s
ao usar (2) operações de gravação em lote~ 1.5s
ao usar operações de gravação individuais paralelasExistem três maneiras comuns de executar um grande número de operações de gravação no Firestore.
Investigaremos cada um deles por vez, usando uma matriz de dados de documentos aleatórios.
Esta é a solução mais simples possível:
async function testSequentialIndividualWrites(datas) {
while (datas.length) {
await collection.add(datas.shift());
}
}
Escrevemos cada documento por vez, até escrevermos todos os documentos. E aguardamos a conclusão de cada operação de gravação antes de iniciar a próxima.
A gravação de 1.000 documentos leva cerca de 105 segundos com essa abordagem; portanto, a taxa de transferência é de aproximadamente 10 gravações de documentos por segundo .
Esta é a solução mais complexa.
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;
}
}
}
Você pode ver que criamos um BatchedWrite
objeto chamando batch()
, preencha-o até sua capacidade máxima de 500 documentos e, em seguida, grave-o no Firestore. Atribuímos a cada documento um nome gerado que é relativamente provável que seja único (bom o suficiente para este teste).
A gravação de 1.000 documentos leva cerca de 2,8 segundos com essa abordagem; portanto, a taxa de transferência é de aproximadamente 357 gravações de documentos por segundo .
Isso é um pouco mais rápido do que com as gravações individuais sequenciais. De fato: muitos desenvolvedores usam essa abordagem porque assumem que é a mais rápida, mas como os resultados acima já mostraram isso não é verdade. E o código é de longe o mais complexo, devido à restrição de tamanho nos lotes.
A documentação do Firestore diz isso sobre o desempenho da adição de muitos dados :
Para entrada de dados em massa, use uma biblioteca-cliente do servidor com gravações individuais paralelas. Gravações em lote têm melhor desempenho do que gravações serializadas, mas não melhor que gravações paralelas.
Podemos colocar isso à prova com este código:
async function testParallelIndividualWrites(datas) {
await Promise.all(datas.map((data) => collection.add(data)));
}
Esse código inicia as add
operações o mais rápido possível e, em seguida, Promise.all()
aguarda até que todas estejam concluídas. Com essa abordagem, as operações podem ser executadas em paralelo.
A gravação de 1.000 documentos leva cerca de 1,5 segundos com essa abordagem; portanto, o rendimento é de aproximadamente 667 gravações de documentos por segundo .
A diferença não é tão grande quanto entre as duas primeiras abordagens, mas ainda é 1,8 vezes mais rápida que as gravações em lote.
Algumas notas:
add()
nada mais do que gerar um ID exclusivo (puramente do lado do cliente), seguido por umaset()
operação. Portanto, os resultados devem ser os mesmos. Se não é o que você observa, poste uma nova pergunta com o mínimo de casos que reproduz o que você tentou.