web-dev-qa-db-fra.com

Firestore lent problème de performance sur l'obtention de données

Firestore rencontre des problèmes de performances lors de la récupération des données de base stockées dans un document par rapport à la base de données en temps réel avec un rapport 1/10.

En utilisant Firestore, il faut en moyenne 3000 ms au premier appel

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

En utilisant la base de données temps réel, il faut en moyenne 300 ms au premier appel

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

Ceci est une capture d'écran de la console réseau:

Firestore slow performance issue get Data

J'utilise le SDK Javascript v4.50 avec AngularFire2 v5.0 rc.2.

Quelqu'un at-il rencontré ce problème?

65
Olivier P

MISE À JOUR: 12 février 2018 - iOS Firestore SDK v0.10.0

À l'instar de certains autres commentateurs, j'ai également remarqué une réponse plus lente lors de la première demande get (les demandes suivantes prenant environ 100 ms). Pour moi, ce n'est pas aussi mauvais que 30 ans, mais peut-être autour de 2-3 quand j'ai une bonne connectivité, ce qui est suffisant pour fournir une mauvaise expérience utilisateur lorsque mon application démarre.

Firebase a fait savoir qu'il était conscient de ce problème de "démarrage à froid" et qu'il travaillait sur une solution à long terme pour le résoudre - malheureusement, pas d'ETA. Je pense que le fait que, lorsque la connectivité est mauvaise, cela peut prendre plusieurs années (plus de 30 ans) avant que les requêtes get ne décident de lire dans le cache.

Alors que Firebase corrige tous ces problèmes, j'ai commencé à utiliser les nouvelles méthodes disableNetwork() et enableNetwork() (disponibles dans Firestore v0.10.0) pour contrôler manuellement l'état en ligne/hors ligne de Firebase. Bien que je devais être très prudent lorsque je l'utilise dans mon code, car il existe un bogue Firestore pouvant provoquer un crash dans certains scénarios.


MISE À JOUR: 15 novembre 2017 - iOS Firestore SDK v0.9.2

Il semble que le problème de performance lente ait été corrigé. J'ai refait les tests décrits ci-dessous et le temps qu'il a fallu à Firestore pour renvoyer les 100 documents semble maintenant être constamment autour de 100 ms.

Vous n'êtes pas sûr qu'il s'agisse d'un correctif dans la dernière version SDK v0.9.2 ou d'un correctif principal (ou des deux), mais je suggère à tout le monde de mettre à jour leurs pods Firebase. Mon application est sensiblement plus réactive - semblable à celle utilisée dans la base de données Realtime.


J'ai également découvert que Firestore était beaucoup plus lent que Realtime DB, en particulier lorsque vous lisiez de nombreux documents.

Tests mis à jour (avec le dernier iOS Firest SDK v0.9.0):

J'ai mis en place un projet de test sous iOS Swift en utilisant à la fois RTDB et Firestore et ai exécuté 100 opérations de lecture séquentielles sur chacune. Pour la RTDB, j'ai testé l'observable ObserverSingleEvent et observer des méthodes sur chacun des 100 nœuds de niveau supérieur. Pour Firestore, j'ai utilisé les méthodes getDocument et addSnapshotListener dans chacun des 100 documents de la collection TestCol. J'ai exécuté les tests avec la persistance du disque sur et en dehors. Veuillez vous reporter à l'image ci-jointe, qui présente la structure de données pour chaque base de données.

J'ai exécuté le test 10 fois pour chaque base de données sur le même appareil et sur un réseau wifi stable. Les observateurs et les auditeurs existants ont été détruits avant chaque nouvelle série.

Méthode Real Time DB observeSingleEvent:

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)")
        }
    }
}

Méthode d'observation de la base de données en temps réel:

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)")
        }
    }
}

Méthode Firestore getDocument:

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)")
        }
    }
}

Méthode Firestore addSnapshotListener:

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)")
        }
    }
}

Chaque méthode imprime essentiellement l’horodatage Unix en millisecondes au début de l’exécution, puis imprime un autre horodatage Unix au retour de chaque opération de lecture. J'ai pris la différence entre l'horodatage initial et le dernier horodatage à retourner.

RESULTATS - Persistance de disque désactivée:

Disk persistence disabled

RESULTATS - Persistance de disque activée:

Disk persistence enabled

Structure de données:

Data Structure

Lorsque les méthodes Firestore getDocument/addSnapshotListener sont bloquées, il semble rester bloqué pendant des durées qui sont à peu près multiples de 30 secondes. Cela pourrait peut-être aider l’équipe de Firebase à identifier où, dans le SDK, il est bloqué?

38
Saul

Date de mise à jour 02 mars 2018

Il semble que ce soit un problème connu et les ingénieurs de Firestore travaillent sur un correctif. Après quelques échanges de courriels et le partage de code avec un ingénieur Firestore sur cette question, voici sa réponse à ce jour.

"Vous avez en fait raison. Après vérification, cette lenteur de l'API getDocuments () est un comportement connu de la version bêta de Cloud Firestore. Nos ingénieurs sont conscients de ce problème de performance appelé" démarrage à froid ", mais ne vous inquiétez pas, comme nous le faisons. notre meilleur pour améliorer les performances des requêtes Firestore.

Nous travaillons déjà sur une solution à long terme, mais je ne peux partager aucun échéancier ni aucune précision pour le moment. Bien que Firestore soit toujours en version bêta, attendez-vous à de nouvelles améliorations. "

Donc j'espère que ça va être assommé bientôt.


tilisation de Swift/iOS

Après avoir traité cette question pendant environ 3 jours, il semble que le problème soit définitivement le get (), à savoir .getDocuments et .getDocument. Les choses que je pensais étaient à l'origine des retards extrêmes mais intermittents mais ne semblent pas être le cas:

  1. Connectivité réseau pas si grande
  2. Appels répétés via une boucle sur .getDocument ()
  3. Chaining get () appelle
  4. Firestore Démarrage à froid
  5. Extraire plusieurs documents (Extraire 1 petit document a provoqué un retard de 20 secondes)
  6. Mise en cache (j'ai désactivé la persistance hors ligne, mais cela n'a rien fait.)

J'ai pu écarter tout cela en constatant que ce problème ne se produisait pas à chaque appel de la base de données Firestore que je passais. Récupérations uniquement à l'aide de get (). Pour les coups de pied, j'ai remplacé .getDocument par .addSnapshotListener pour récupérer mes données et le tour est joué. Récupération instantanée à chaque fois, y compris le premier appel. Pas de démarrage à froid. Jusqu'à présent, aucun problème avec .addSnapshotListener, seulement getDocument (s).

Pour le moment, je laisse simplement tomber le .getDocument () où le temps est compté et le remplace par .addSnapshotListener puis en utilisant

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

... afin de continuer à bouger jusqu'à ce que Firestore s'en occupe.

17
Terrence

J'ai eu ce problème jusqu'à ce matin. Ma requête Firestore via iOS/Swift prend environ 20 secondes pour compléter une requête simple, entièrement indexée - avec des temps de requête non proportionnels pour 1 élément renvoyé - jusqu'à 3 000.

Ma solution consistait à désactiver la persistance des données hors connexion. Dans mon cas, cela ne répondait pas aux besoins de notre base de données Firestore - qui contient une grande partie de ses données mises à jour quotidiennement.

les utilisateurs iOS & Android ont cette option activée par défaut, tandis que les utilisateurs Web l’ont désactivée par défaut. Firestore semble incroyablement lent si vous interrogez une énorme collection de documents. Fondamentalement, il met en cache une copie des données interrogées (et de la collection interrogée - je crois qu'il cache tous les documents qu'il contient), ce qui peut entraîner une utilisation élevée de la mémoire.

Dans mon cas, cela a provoqué une attente énorme pour chaque requête jusqu'à ce que le périphérique mette en cache les données requises - d'où le temps de requête non proportionnel pour le nombre croissant d'éléments à renvoyer de la même collection. En effet, la mise en cache de la collection dans chaque requête a pris le même temps.

Données hors connexion - à partir des documents Cloud Firestore

J'ai effectué des analyses comparatives pour afficher cet effet (avec la persistance hors connexion activée) à partir de la même collection interrogée, mais avec différentes quantités d'éléments renvoyées à l'aide du paramètre .limit:

Benchmarks Maintenant que 100 éléments sont retournés (avec la persistance hors ligne désactivée), ma requête prend moins d'une seconde à compléter.

Mon code de requête Firestore est ci-dessous:

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

eh bien, de ce que je fais actuellement et de la recherche en utilisant Nexus 5X dans un émulateur et réel Android téléphone Huawei P8,

Firestore et Cloud Storage me donnent un mal de tête de réponse lente quand je fais d'abord le document.get () et le premier storage.getDownloadUrl ()

Cela me donne plus de 60 secondes de réponse pour chaque demande. La réponse lente ne se produit que sur les vrais téléphones Android. Pas dans l'émulateur. Une autre chose étrange. Après la première rencontre, la demande de repos est lisse.

Voici le code simple où je rencontre la réponse lente.

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

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

J'ai également trouvé le lien qui recherche le même. https://reformatcode.com/code/Android/firestore-document-get-performance

1
Kyo Kurosagi