wake-up-neo.com

Langsame Firestore-Leistung beim Abrufen von Daten

Ich habe Probleme mit der langsamen Leistung von Firestore beim Abrufen der in einem Dokument gespeicherten Basisdaten im Vergleich zur Echtzeitdatenbank mit einem Verhältnis von 1/10.

Bei Verwendung von Firestore dauert es beim ersten Aufruf durchschnittlich 3000 ms

 this.db.collection(‘testCol’)
   .doc(‘testDoc’)
   .valueChanges().forEach((data) => {
     console.log(data);//3000 ms later
 });

Bei Verwendung der Echtzeitdatenbank werden beim ersten Aufruf durchschnittlich 300 ms benötigt

 this.db.database.ref(‘/test’).once(‘value’).then(data => {
     console.log(data); //300ms later
 });

Dies ist ein Screenshot der Netzwerkkonsole:

Firestore slow performance issue get Data

Ich verwende das Javascript SDK v4.50 mit AngularFire2 v5.0 rc.2.

Hat jemand dieses Problem erlebt?

65
Olivier P

UPDATE: 12. Februar 2018 - iOS Firestore SDK v0.10.0

Ähnlich wie bei einigen anderen Kommentatoren ist mir auch bei der ersten Get-Anforderung eine langsamere Antwort aufgefallen (wobei nachfolgende Anforderungen ~ 100 ms dauern). Für mich ist es nicht so schlimm wie in den 30ern, aber vielleicht in den 2-3ern, wenn ich eine gute Konnektivität habe. Dies reicht aus, um beim Start meiner App eine schlechte Benutzererfahrung zu erzielen.

Firebase hat mitgeteilt, dass sie sich dieses "Kaltstart" -Problems bewusst sind und daran arbeiten, es langfristig zu beheben - leider keine ETA. Ich denke, es ist ein separates Problem, dass es bei einer schlechten Konnektivität einige Zeit dauern kann (über 30 Sekunden), bis sich Anfragen zum Lesen aus dem Cache entschließen.

Während Firebase all diese Probleme behebt, habe ich begonnen, die neuen Methoden disableNetwork() und enableNetwork() (verfügbar in Firestore v0.10.0) zu verwenden, um den Online-/Offline-Status von Firebase manuell zu steuern. Obwohl ich sehr vorsichtig sein musste, wo ich es in meinem Code verwende, da es einen Firestore-Fehler gibt, der unter bestimmten Szenarien einen Absturz verursachen kann.


UPDATE: 15. November 2017 - iOS Firestore SDK v0.9.2

Es scheint, dass das Problem mit der langsamen Leistung jetzt behoben wurde. Ich habe die unten beschriebenen Tests wiederholt und die Zeit, die Firestore benötigt, um die 100 Dokumente zurückzugeben, scheint nun konsistent bei 100 ms zu liegen.

Ich bin mir nicht sicher, ob dies ein Fix im neuesten SDK v0.9.2 oder ein Backend-Fix (oder beides) war, aber ich schlage vor, dass jeder seine Firebase-Pods aktualisiert. Meine App reagiert spürbar schneller - ähnlich wie bei der Realtime DB.


Ich habe auch festgestellt, dass Firestore viel langsamer als Realtime DB ist, insbesondere beim Lesen aus vielen Dokumenten.

Aktualisierte Tests (mit dem neuesten iOS Firestore SDK v0.9.0):

Ich habe ein Testprojekt in iOS Swift sowohl mit RTDB als auch mit Firestore eingerichtet und jeweils 100 sequenzielle Leseoperationen ausgeführt. Für die RTDB habe ich das observSingleEvent und die observ-Methoden auf jeder der 100 obersten Ebenen getestet Für Firestore habe ich die Methoden getDocument und addSnapshotListener für jedes der 100 Dokumente in der TestCol-Auflistung verwendet. Ich habe die Tests mit Datenträgerpersistenz ein- und ausgeschaltet. Siehe das angehängte Bild, das die Datenstruktur für jede Datenbank zeigt.

Ich habe den Test 10 Mal für jede Datenbank auf demselben Gerät und einem stabilen WLAN-Netzwerk ausgeführt. Bestehende Beobachter und Zuhörer wurden vor jedem neuen Lauf zerstört.

Echtzeit-DB observSingleEvent-Methode:

func rtdbObserveSingle() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from RTDB at: \(start)")

    for i in 1...100 {
        Database.database().reference().child(String(i)).observeSingleEvent(of: .value) { snapshot in
            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            let data = snapshot.value as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Echtzeit-DB-Beobachtungsmethode:

func rtdbObserve() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from RTDB at: \(start)")

    for i in 1...100 {
        Database.database().reference().child(String(i)).observe(.value) { snapshot in
            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            let data = snapshot.value as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Firestore getDocument-Methode:

func fsGetDocument() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from FS at: \(start)")

    for i in 1...100 {
        Firestore.firestore().collection("TestCol").document(String(i)).getDocument() { document, error in

            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            guard let document = document, document.exists && error == nil else {
                print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
                return
            }
            let data = document.data() as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Firestore addSnapshotListener-Methode:

func fsAddSnapshotListener() {

    let start = UInt64(floor(Date().timeIntervalSince1970 * 1000))
    print("Started reading from FS at: \(start)")

    for i in 1...100 {
        Firestore.firestore().collection("TestCol").document(String(i)).addSnapshotListener() { document, error in

            let time = UInt64(floor(Date().timeIntervalSince1970 * 1000))
            guard let document = document, document.exists && error == nil else {
                print("Error: \(error?.localizedDescription ?? "nil"). Returned at: \(time)")
                return
            }
            let data = document.data() as? [String: String] ?? [:]
            print("Data: \(data). Returned at: \(time)")
        }
    }
}

Jede Methode druckt im Wesentlichen den Unix-Zeitstempel in Millisekunden, wenn die Methode mit der Ausführung beginnt, und druckt dann einen weiteren Unix-Zeitstempel, wenn jede Leseoperation zurückkehrt. Ich habe die Differenz zwischen dem anfänglichen Zeitstempel und dem letzten zurückgegebenen Zeitstempel genommen.

ERGEBNISSE - Festplattenpersistenz deaktiviert:

Disk persistence disabled

ERGEBNISSE - Festplattenpersistenz aktiviert:

Disk persistence enabled

Datenstruktur:

Data Structure

Wenn die Firestore-Methode getDocument/addSnapshotListener nicht mehr reagiert, scheint sie für eine Dauer von ungefähr einem Vielfachen von 30 Sekunden nicht mehr zu funktionieren. Vielleicht könnte dies dem Firebase-Team helfen, herauszufinden, wo es im SDK hängen bleibt?

38
Saul

Aktualisierung am 02. März 2018

Es sieht so aus, als ob dies ein bekanntes Problem ist und die Ingenieure von Firestore arbeiten an einer Lösung. Nach ein paar E-Mails und dem Austausch von Code mit einem Firestore-Techniker zu diesem Thema war dies seine Antwort bis heute.

"Sie haben tatsächlich Recht. Nach weiteren Überprüfungen ist diese Verlangsamung der getDocuments () - API ein bekanntes Verhalten in der Beta von Cloud Firestore. Unsere Techniker sind sich dieses als" Kaltstart "gekennzeichneten Leistungsproblems bewusst, machen sich jedoch keine Sorgen unser Bestes, um die Leistung von Firestore-Abfragen zu verbessern.

Wir arbeiten bereits an einer langfristigen Lösung, aber ich kann im Moment keine Zeitpläne oder Einzelheiten mitteilen. Während sich Firestore noch in der Beta-Phase befindet, ist mit weiteren Verbesserungen zu rechnen. "

Hoffentlich ist dies bald erledigt.


Mit Swift/iOS

Nach ca. 3 Tagen scheint das Problem definitiv get () zu sein, dh .getDocuments und .getDocument. Dinge, von denen ich dachte , dass sie die extremen und dennoch zeitweiligen Verzögerungen verursachen, aber anscheinend nicht der Fall sind:

  1. Nicht so gute Netzwerkkonnektivität
  2. Wiederholte Aufrufe per Loop über .getDocument ()
  3. Verkettung von get () -Aufrufen
  4. Firestore Kaltstart
  5. Abrufen mehrerer Dokumente (Das Abrufen eines kleinen Dokuments verursachte eine Verzögerung von 20 Sekunden.)
  6. Caching (Ich habe die Offline-Persistenz deaktiviert, aber dies hat nichts bewirkt.)

Ich konnte all dies ausschließen, da ich bemerkte, dass dieses Problem nicht bei jedem Firestore-Datenbankaufruf auftrat, den ich machte. Nur Abfragen mit get (). Für Kicks habe ich .getDocument durch .addSnapshotListener ersetzt, um meine Daten und Voila abzurufen. Sofortiger Abruf jedes Mal, einschließlich des ersten Anrufs. Kein Kaltstart. Bisher keine Probleme mit dem .addSnapshotListener, nur getDocument (s).

Im Moment lasse ich einfach das .getDocument () fallen, wo es auf die Zeit ankommt, und ersetze es durch .addSnapshotListener und verwende es dann

for document in querySnapshot!.documents{
// do some magical Unicorn stuff here with my document.data()
}

... um in Bewegung zu bleiben, bis dies von Firestore geklärt wird.

17
Terrence

Ich hatte dieses Problem bis heute Morgen. Meine Firestore-Abfrage über iOS/Swift würde etwa 20 Sekunden dauern, um eine einfache, vollständig indizierte Abfrage mit nicht proportionalen Abfragezeiten für 1 zurückgegebenen Artikel bis zu 3.000 abzuschließen.

Meine Lösung bestand darin, die Offline-Datenpersistenz zu deaktivieren. In meinem Fall entsprach es nicht den Anforderungen unserer Firestore-Datenbank, in der große Teile der Daten jeden Tag aktualisiert werden.

iOS & Android Benutzer haben diese Option standardmäßig aktiviert, während Webbenutzer sie standardmäßig deaktiviert haben. Dadurch wirkt Firestore wahnsinnig langsam, wenn Sie eine große Sammlung von Dokumenten abfragen. Grundsätzlich wird a zwischengespeichert Kopie der von Ihnen abgefragten Daten (und der von Ihnen abgefragten Sammlung - ich glaube, sie speichert alle darin enthaltenen Dokumente im Cache), was zu einer hohen Speichernutzung führen kann.

In meinem Fall verursachte es eine enorme Wartezeit für jede Abfrage, bis das Gerät die erforderlichen Daten zwischengespeichert hatte - daher die nicht proportionalen Abfragezeiten für die steigende Anzahl von Elementen, die aus genau derselben Sammlung zurückgegeben wurden. Dies liegt daran, dass das Zwischenspeichern der Auflistung in jeder Abfrage genauso lange gedauert hat.

Offline-Daten - aus den Cloud Firestore-Dokumenten

Ich habe ein Benchmarking durchgeführt, um diesen Effekt (mit aktivierter Offline-Persistenz) aus derselben abgefragten Sammlung anzuzeigen, aber mit unterschiedlichen Mengen von Elementen, die mit dem Parameter .limit zurückgegeben wurden:

Benchmarks Bei 100 zurückgegebenen Elementen (mit deaktivierter Offline-Persistenz) dauert der Abschluss meiner Abfrage weniger als 1 Sekunde.

Mein Firestore-Abfragecode lautet wie folgt:

let db = Firestore.firestore()
self.date = Date()
let ref = db.collection("collection").whereField("Int", isEqualTo: SomeInt).order(by: "AnotherInt", descending: true).limit(to: 100)
ref.getDocuments() { (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
        for document in querySnapshot!.documents {
            let data = document.data()
            //Do things
        }
        print("QUERY DONE")
        let currentTime = Date()
        let components = Calendar.current.dateComponents([.second], from: self.date, to: currentTime)
        let seconds = components.second!
        print("Elapsed time for Firestore query -> \(seconds)s")
        // Benchmark result
    }
}
7
Hendies

nun, von dem, was ich gerade mache und recherchiere, indem ich Nexus 5X in Emulator und Real verwende Android Telefon Huawei P8,

Sowohl Firestore als auch Cloud Storage verursachen bei der ersten Ausführung von document.get () und storage.getDownloadUrl () Kopfschmerzen bei langsamen Reaktionen.

Es gibt mir mehr als 60 Sekunden Antwort auf jede Anfrage. Die langsame Antwort nur in realen Android nicht im Emulator. Eine andere seltsame Sache. Nach der ersten Begegnung ist die Restanforderung glatt.

Hier ist der einfache Code, in dem ich die langsame Antwort treffe.

var dbuserref = dbFireStore.collection('user').where('email','==',email);
const querySnapshot = await dbuserref.get();

var url = await defaultStorage.ref(document.data().image_path).getDownloadURL();

Ich habe auch einen Link gefunden, der dasselbe erforscht. https://reformatcode.com/code/Android/firestore-document-get-performance

1
Kyo Kurosagi