Qual è il modo più veloce per scrivere molti documenti su Firestore?


Risposte:


26

TL; DR: il modo più rapido per eseguire la creazione di date in serie su Firestore è eseguire singole operazioni di scrittura parallele.

Scrivere 1.000 documenti su Firestore richiede:

  1. ~105.4s quando si utilizzano operazioni di scrittura sequenziali individuali
  2. ~ 2.8s quando si utilizzano (2) operazioni di scrittura in batch
  3. ~ 1.5s quando si utilizzano operazioni di scrittura individuali parallele

Esistono tre modi comuni per eseguire un gran numero di operazioni di scrittura su Firestore.

  1. Eseguire ogni singola operazione di scrittura in sequenza.
  2. Utilizzo di operazioni di scrittura in batch.
  3. Esecuzione di singole operazioni di scrittura in parallelo.

Analizzeremo ciascuno a turno di seguito, utilizzando una matrice di dati del documento randomizzati.


Operazioni individuali di scrittura sequenziale

Questa è la soluzione più semplice possibile:

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

Scriviamo ogni documento a turno, fino a quando non abbiamo scritto ogni documento. E aspettiamo che ogni operazione di scrittura venga completata prima di iniziare quella successiva.

La scrittura di 1.000 documenti richiede circa 105 secondi con questo approccio, quindi la velocità effettiva è di circa 10 scritture di documenti al secondo .


Utilizzo di operazioni di scrittura in batch

Questa è la soluzione più complessa.

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;
    }
  }
}

Puoi vedere che creiamo un BatchedWriteoggetto chiamandobatch() , riempilo fino alla sua capacità massima di 500 documenti, quindi scrivilo su Firestore. Diamo a ciascun documento un nome generato che è relativamente probabile che sia univoco (abbastanza buono per questo test).

La scrittura di 1.000 documenti richiede circa 2,8 secondi con questo approccio, quindi la velocità effettiva è di circa 357 scritture di documenti al secondo .

È un po 'più veloce rispetto alle singole scritture sequenziali. In effetti: molti sviluppatori usano questo approccio perché presumono che sia il più veloce, ma poiché i risultati di cui sopra hanno già dimostrato che ciò non è vero. E il codice è di gran lunga il più complesso, a causa del vincolo di dimensione sui batch.


Operazioni di scrittura individuali parallele

La documentazione di Firestore dice questo sulle prestazioni per l'aggiunta di molti dati :

Per l'immissione di dati in blocco, utilizzare una libreria client del server con scritture individuali parallelizzate. Le scritture in batch funzionano meglio delle scritture serializzate ma non meglio delle scritture parallele.

Possiamo metterlo alla prova con questo codice:

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

Questo codice adddà il via alle operazioni il più velocemente possibile e quindi usa Promise.all()per attendere fino a quando non sono finite tutte. Con questo approccio le operazioni possono essere eseguite in parallelo.

La scrittura di 1.000 documenti richiede circa 1,5 secondi con questo approccio, quindi la velocità effettiva è di circa 667 scritture di documenti al secondo .

La differenza non è così grande come tra i primi due approcci, ma è ancora oltre 1,8 volte più veloce delle scritture in batch.


Alcune note:

  • Puoi trovare il codice completo di questo test su Github .
  • Mentre il test è stato eseguito con Node.js, è probabile che tu ottenga risultati simili su tutte le piattaforme supportate da Admin SDK.
  • Tuttavia, non eseguire inserimenti di massa utilizzando gli SDK client, poiché i risultati potrebbero essere molto diversi e molto meno prevedibili.
  • Come al solito, le prestazioni effettive dipendono dalla macchina, dalla larghezza di banda e dalla latenza della connessione Internet e da molti altri fattori. Sulla base di questi, potresti notare differenze anche nelle differenze, anche se mi aspetto che l'ordinamento rimanga lo stesso.
  • Se hai dei valori anomali nei tuoi test o trovi risultati completamente diversi, lascia un commento qui sotto.
  • Le scritture in batch sono atomiche. Pertanto, se si hanno dipendenze tra i documenti e tutti i documenti devono essere scritti o nessuno di essi deve essere scritto, è necessario utilizzare una scrittura in batch.

1
Questo è molto interessante, grazie per aver svolto il lavoro! OOC, hai testato l'esecuzione delle scritture in batch in parallelo? Ovviamente, in quel caso dovresti essere ancora più sicuro di evitare che qualsiasi documento sia presente in entrambi i lotti.
robsiemb,

1
Stavo per testare le scritture in batch parallele, ma ho esaurito le quote (è un progetto gratuito ed ero troppo pigro per l'aggiornamento). Oggi è un altro giorno, quindi potrei provare e aggiornare la mia risposta se è significativa.
Frank van Puffelen,

2
@robsiemb Ho appena provato anche con scritture in batch parallele. Le prestazioni sono molto simili alle singole scritture parallele, quindi direi che sono legate per prime nei miei test. Mi aspetto che le scritture in batch possano deteriorarsi più rapidamente a causa della natura che vengono elaborate sul back-end. Combinato con il codice molto più complesso, consiglierei comunque di usarli solo per la loro atomicità e non per il vantaggio prestazionale percepito ma inesistente.
Frank van Puffelen,

Le scritture parallele di @FrankvanPuffelen saranno più veloci anche se "imposto" documenti anziché "aggiungi" documenti? Voglio dire, db.collection ('città'). Doc ('LA'). Set (data) invece di db.collection ('città'). Add (data)
alek6dj

La chiamata add()non fa altro che generare un ID univoco (puramente lato client), seguito da set()un'operazione. Quindi i risultati dovrebbero essere gli stessi. Se non è quello che osservi, pubblica una nuova domanda con il caso minimo che riproduce ciò che hai provato.
Frank van Puffelen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.