85 votes

Firestore : problème de lenteur dans l'obtention des données

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

Avec Firestore, le premier appel prend en moyenne 3000 ms.

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

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

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

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

Firestore slow performance issue get Data

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

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

0 votes

Quelles performances constatez-vous si vous effectuez un deuxième appel (vers un autre document / collection) ? Le même problème se pose-t-il si vous n'utilisez pas angularfire ?

0 votes

J'ai une expérience similaire. Le premier appel est un peu lent, 5-10s parfois. Je suis en train de créer une application de chat - le premier message met un certain temps à arriver, mais les suivants sont presque instantanés. Firestore est encore en version bêta, ils sont probablement encore en train de régler les problèmes.

1 votes

Expérience similaire ici. Le premier onSnapShot prend un temps fou - jusqu'à 2 minutes pour certains utilisateurs - ce qui rend notre application inutilisable.

48voto

Saul Points 670

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

Comme d'autres commentateurs, j'ai également remarqué un ralentissement de la réponse lors de la première demande d'accès (les demandes suivantes prenant ~100 ms). Pour moi, ce n'est pas aussi grave que 30s, mais peut-être autour de 2-3s lorsque 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'ils sont conscients de ce problème de "démarrage à froid" et qu'ils travaillent sur une solution à long terme - pas d'ETA malheureusement. Je pense que c'est un problème distinct que lorsque j'ai une mauvaise connectivité, il peut prendre des âges (plus de 30s) avant d'obtenir des demandes de décider de lire à partir du cache.

En attendant que Firebase corrige tous ces problèmes, j'ai commencé à utiliser la nouvelle fonction disableNetwork() y enableNetwork() (disponible dans Firestore v0.10.0) pour contrôler manuellement l'état en ligne/hors ligne de Firebase. Bien que j'aie dû très attention à l'endroit où je l'utilise dans mon code, car il existe un bogue de Firestore qui peut provoquer un crash dans certains scénarios.


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

Il semble que le problème de lenteur des performances soit maintenant résolu. J'ai refait les tests décrits ci-dessous et le temps nécessaire à Firestore pour renvoyer les 100 documents semble maintenant se situer autour de 100 ms.

Je ne sais pas si c'était un correctif dans le dernier SDK v0.9.2 ou si c'était un correctif backend (ou les deux), mais je suggère que tout le monde mette à jour ses pods Firebase. Mon application est nettement plus réactive, comme elle l'était avec la Realtime DB.


J'ai également découvert que Firestore est beaucoup plus lent que Realtime DB, en particulier lors de la lecture de nombreux documents.

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

J'ai mis en place un projet de test dans iOS Swift en utilisant à la fois RTDB et Firestore et j'ai exécuté 100 opérations de lecture séquentielles sur chacun. Pour RTDB, j'ai testé les méthodes observeSingleEvent et observe sur chacun des 100 nœuds de niveau supérieur. Pour Firestore, j'ai utilisé les méthodes getDocument et addSnapshotListener sur chacun des 100 documents de la collection TestCol. J'ai effectué les tests avec la persistance sur disque activée et désactivée. Veuillez vous référer à l'image jointe, qui montre la structure des données pour chaque base de données.

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

Méthode Realtime 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 DB 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 getDocument de Firestore :

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 lorsque la méthode commence à s'exécuter, puis imprime un autre horodatage unix lorsque chaque opération de lecture revient. J'ai pris la différence entre le timestamp initial et le dernier timestamp à retourner.

RÉSULTATS - La persistance du disque est désactivée :

Disk persistence disabled

RÉSULTATS - Persistance du disque activée :

Disk persistence enabled

Structure des données :

Data Structure

Lorsque les méthodes getDocument / addSnapshotListener de Firestore se bloquent, elles semblent se bloquer pendant des durées qui sont approximativement des multiples de 30 secondes. Peut-être cela pourrait-il aider l'équipe de Firebase à isoler l'endroit du SDK où le blocage se produit ?

3 votes

Donc firestore est plus cher et beaucoup plus lent Espérons que l'équipe de firebase voit cela

7 votes

[Merci de prendre le temps de fournir des données aussi détaillées, nous apprécions toujours cela. Le problème n'est pas que le système est "plus lent", mais qu'un très petit nombre de requêtes restent bloquées ou prennent énormément de temps à revenir. Nous avons prévu d'apporter prochainement des correctifs qui devraient améliorer la situation.

1 votes

Merci de nous tenir au courant. J'ai ajouté de nouveaux résultats pour la dernière version du SDK Firestore v0.9.0, qui pourraient aider votre équipe à isoler la source du problème. J'ai également rencontré un autre problème avec le snapshot listener : stackoverflow.com/questions/46710371/ La cause profonde peut ou non être liée à ce sujet, mais ce serait formidable si l'équipe Firebase pouvait y jeter un coup d'œil. Merci beaucoup !

23voto

Terrence Points 171

Date de mise à jour : 02 mars 2018

Il semble que ce soit un problème connu et que les ingénieurs de Firestore travaillent sur une solution. Après quelques échanges d'emails et un partage de code avec un ingénieur de Firestore sur ce problème, voici sa réponse à ce jour.

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

Nous travaillons déjà sur une solution à long terme, mais je ne peux pas vous communiquer de calendrier ou de détails pour le moment. Bien que Firestore soit encore en version bêta, attendez-vous à ce qu'il y ait d'autres améliorations à venir."

J'espère que ça sera bientôt réglé.


Utilisation de Swift / iOS

Après avoir traité ce problème pendant environ 3 jours, il semble que le problème vienne de la méthode get(), c'est-à-dire .getDocuments et .getDocument. Les choses que j'ai pensée étaient à l'origine des retards extrêmes mais intermittents, mais cela ne semble pas être le cas :

  1. Connectivité réseau pas très bonne
  2. Appels répétés via le bouclage de .getDocument()
  3. Enchaînement des appels get()
  4. Firestore Démarrage à froid
  5. Récupération de plusieurs documents (la récupération d'un petit document entraînait des retards de 20 secondes).
  6. Mise en cache (j'ai désactivé la persistance hors ligne mais cela n'a rien donné).

J'ai pu exclure toutes ces possibilités car j'ai remarqué que ce problème ne se produisait pas avec chaque appel de base de données Firestore que je faisais. Seulement avec les récupérations utilisant get(). Pour le plaisir, j'ai remplacé .getDocument par .addSnapshotListener pour récupérer mes données et voilà. Récupération instantanée à chaque fois, y compris lors du premier appel. Pas de démarrage à froid. Jusqu'à présent, aucun problème avec le .addSnapshotListener, seulement avec getDocument(s).

Pour l'instant, j'abandonne simplement la fonction .getDocument() lorsque le temps est compté et je la remplace par .addSnapshotListener, puis j'utilise la fonction

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

... afin de continuer à avancer jusqu'à ce que tout soit réglé par Firestore.

0 votes

Je constate le même comportement, mais uniquement sous Android. Pour l'instant, je me rabats également sur les snapshots. Mais il serait bon que les performances des requêtes get soient cohérentes.

0 votes

Je constate également une lenteur des performances avec l'adaptateur de recyclage FirebaseUI, qui utilise addSnapshotListener.

0 votes

Ce problème de "démarrage à froid" existe-t-il toujours ? Je suis un peu confus par votre mise à jour de mars mentionnant que les ingénieurs de Firebase sont conscients de ce qu'ils appellent un problème de "démarrage à froid", car dans votre réponse initiale vous avez écrit que vous aviez exclu "4. Firestore Cold starting" comme étant le problème ?

12voto

JPJ Points 81

Presque 3 ans plus tard, firestore étant bien sorti de sa phase bêta et je peux confirmer que cet horrible problème persiste ;-(

Sur notre application mobile, nous utilisons le client firebase javascript / node.js. Après de nombreux tests pour trouver pourquoi le temps de démarrage de notre application est d'environ 10 secondes, nous avons identifié à quoi attribuer 70% de ce temps... Eh bien, aux problèmes de performance et de démarrage à froid de Firebase et Firestore :

  • firebase.auth().onAuthStateChanged() se déclenche environ après 1,5 - 2sec, ce qui est déjà très mauvais.
  • S'il retourne un utilisateur, nous utilisons son ID pour obtenir le document de l'utilisateur de firestore. Il s'agit du premier appel à firestore et le get() correspondant prend 4 à 5 secondes. Les get() ultérieurs du même document ou d'autres documents prennent environ 500 ms.

Au total, l'initialisation de l'utilisateur prend 6 à 7 secondes, ce qui est totalement inacceptable. Et nous ne pouvons rien y faire. Nous ne pouvons pas tester la désactivation de la persistance, puisque dans le client javascript il n'y a pas une telle option, la persistance est toujours activée par défaut, donc ne pas appeler enablePersistence() ne changera rien.

0 votes

Y a-t-il une solution à ce problème ? Des indications sur les endroits où chercher des réponses seraient grandement appréciées.

0 votes

Dans le client javascript, il est désactivé par défaut : For the web, offline persistence is disabled by default. To enable persistence, call the enablePersistence method mais je peux confirmer qu'en le désactivant, nos temps de requête initiaux passent d'environ 8 secondes à environ 500 ms. firebase.google.com/docs/firestore/manage-data/enable-offline

0 votes

C'est exact, en javascript c'est désactivé par défaut, et les temps que je mentionne ci-dessus sont avec le réglage par défaut. Et dans notre cas, nous avons besoin de données fraîches et mises à jour sur le profil de l'utilisateur, donc l'utilisation de la persistance n'est pas une option.

8voto

Hendies Points 179

J'avais ce problème jusqu'à ce matin. Ma requête Firestore via iOS/Swift prenait environ 20 secondes pour effectuer une requête simple, entièrement indexée - avec des temps de requête non proportionnels pour un élément retourné - jusqu'à 3 000.

Ma solution a été de désactiver la persistance des données hors ligne. Dans mon cas, cela ne répondait pas aux besoins de notre base de données Firestore, dont une grande partie des données est mise à jour quotidiennement.

Les utilisateurs d'iOS et d'Android ont cette option activée par défaut, tandis que les utilisateurs du web l'ont désactivée par défaut. Elle rend Firestore incroyablement lent si vous interrogez une énorme collection de documents. En fait, il met en cache une copie des données que vous interrogez (et de la collection que vous interrogez - je crois qu'il met en cache tous les documents), 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 dispositif ait mis en cache les données requises - d'où les temps de requête non proportionnels pour les nombres croissants d'éléments à retourner à partir de la même collection. Cela s'explique par le fait que la mise en cache de la collection a pris le même temps à chaque requête.

Données hors ligne - à partir des documents de Cloud Firestore

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

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

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

0 votes

Ces chiffres de test proviennent-ils du Web, d'iOS ou d'Android ?

0 votes

Le benchmark provient d'iOS, bien que je m'attende à des gains de performance sur toutes les plateformes - en fonction de la taille de votre collection interrogée.

0 votes

Je n'avais pas réalisé que vous étiez dans l'équipe Firebase ! Le problème de cette requête était que l'utilisation de la mémoire atteignait des chiffres élevés (600-700 mb de RAM) alors que je supposais que notre collection était stockée en cache. La requête se bloquait toujours, puis se terminait une fois que la mémoire augmentait progressivement pour atteindre le même point (700 Mo environ). Après avoir désactivé la persistance, cet effet a cessé et notre mémoire est restée comme prévu (100-150mb), tout en retournant nos résultats super rapidement. Si vous avez besoin de plus d'informations, n'hésitez pas à demander.

1voto

Kyo Kurosagi Points 526

Eh bien, d'après ce que je fais actuellement et mes recherches en utilisant le nexus 5X dans l'émulateur et le vrai téléphone Android Huawei P8,

Firestore et Cloud Storage me donnent tous deux un mal de tête dû à la lenteur des réponses. lorsque je fais d'abord document.get() et ensuite storage.getDownloadUrl()

Il me donne plus de 60 secondes de réponse à chaque demande. La lenteur de la réponse ne se produit que sur un vrai téléphone Android. Pas dans l'émulateur. Une autre chose étrange. Après la première rencontre, le reste des requêtes se passe bien.

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é un lien qui fait des recherches dans le même sens. https://reformatcode.com/code/Android/firestore-document-get-performance

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X