Muszę napisać dużą liczbę dokumentów do Firestore.
Jaki jest najszybszy sposób na to w Node.js?
Muszę napisać dużą liczbę dokumentów do Firestore.
Jaki jest najszybszy sposób na to w Node.js?
Odpowiedzi:
TL; DR: Najszybszym sposobem na utworzenie daty zbiorczej w Firestore jest wykonanie równoległych pojedynczych operacji zapisu.
Napisanie 1000 dokumentów do Firestore wymaga:
~105.4s
podczas korzystania z sekwencyjnych pojedynczych operacji zapisu~ 2.8s
przy użyciu (2) operacji zapisu wsadowego~ 1.5s
podczas korzystania z równoległych pojedynczych operacji zapisuIstnieją trzy typowe sposoby wykonywania dużej liczby operacji zapisu w Firestore.
Zbadamy kolejno każdą z nich, korzystając z szeregu losowych danych dokumentów.
To jest najprostsze możliwe rozwiązanie:
async function testSequentialIndividualWrites(datas) {
while (datas.length) {
await collection.add(datas.shift());
}
}
Piszemy każdy dokument po kolei, dopóki nie napisamy każdego dokumentu. I czekamy na zakończenie każdej operacji zapisu, zanim zaczniemy następną.
Przy takim podejściu pisanie 1000 dokumentów zajmuje około 105 sekund, więc przepustowość wynosi około 10 zapisów dokumentów na sekundę .
To jest najbardziej złożone rozwiązanie.
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;
}
}
}
Możesz zobaczyć, że tworzymy BatchedWrite
obiekt, dzwoniąc batch()
, wypełniając go do maksymalnej pojemności 500 dokumentów, a następnie zapisując go w Firestore. Każdemu dokumentowi nadajemy wygenerowaną nazwę, która prawdopodobnie będzie unikatowa (wystarczająca do tego testu).
Przy takim podejściu napisanie 1000 dokumentów zajmuje około 2,8 sekundy, więc przepustowość wynosi około 357 zapisów dokumentów na sekundę .
To jest trochę szybsze niż w przypadku sekwencyjnych indywidualnych zapisów. W rzeczywistości: wielu programistów stosuje to podejście, ponieważ zakłada, że jest ono najszybsze, ale jak pokazały już powyższe wyniki, nie jest to prawdą. A kod jest zdecydowanie najbardziej złożony, ze względu na ograniczenie wielkości partii.
Dokumentacja Firestore mówi o wydajności dodawania dużej ilości danych :
Do masowego wprowadzania danych użyj biblioteki klienta serwera z równoległymi zapisami pojedynczymi. Zapisy partiami działają lepiej niż zapisy serializowane, ale nie lepiej niż zapisy równoległe.
Możemy to przetestować za pomocą tego kodu:
async function testParallelIndividualWrites(datas) {
await Promise.all(datas.map((data) => collection.add(data)));
}
Ten kod uruchamia add
operacje tak szybko, jak to możliwe, a następnie używa Promise.all()
do czekania, aż wszystkie zostaną zakończone. Przy takim podejściu operacje mogą przebiegać równolegle.
Przy takim podejściu napisanie 1000 dokumentów zajmuje około 1,5 sekundy, więc przepustowość wynosi około 667 zapisów dokumentów na sekundę .
Różnica nie jest prawie tak duża, jak między dwoma pierwszymi podejściami, ale wciąż jest ponad 1,8 razy szybsza niż zapisy partiami.
Kilka uwag:
add()
nie robi nic więcej niż generowanie unikalnego identyfikatora (wyłącznie po stronie klienta), po którym następuje set()
operacja. Wyniki powinny być takie same. Jeśli nie tego obserwujesz, opublikuj nowe pytanie z minimalną kopią, która odtwarza to, czego próbowałeś.