Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore document get() performance

Just starting to explore Firestore storage and first thing to do - read a simple small document in my Android app by document key (authenticated with Google, but probably that's not important). Here is a snippet:

public void readDoc(final String key) {
  final long start = System.currentTimeMillis();
  docsCollection.document(key).get().addOnCompleteListener(
      new OnCompleteListener<DocumentSnapshot>() {
        @Override public void onComplete(@NonNull Task<DocumentSnapshot> task) {
          long end = System.currentTimeMillis();
          Log.d("FirestoreStorage", "get() time: " + (end - start));
        }
      });
}

Here is what I see in LogCat:

10-10 22:30:06.026 D/FirestoreStorage: get() time: 1666
10-10 22:30:08.199 D/FirestoreStorage: get() time: 264

The first read is always very slow, subsequent reads are about 200ms. The document is really small, currently it's just 4 properties and only one (int) is non-null, so the size is not an issue. Running the app on a real phone, Nexus 6 on Android 7.1

Question: what am I doing wrong? I'm basically using a sample from "Getting data" of the How-to Guide.

A read like this should take 0 milliseconds. If there's no workaround, I guess I have to give up the idea of Realtime storage as the only storage for the app and get back to plain SQLite and use Firebase/Firestore as a separate cloud storage.

UPDATE Starting from version 16.0.0 DocumentReference.get() and Query.get() have a new parameter "source" that allows to control where the data is read from - only server, only cache or try server then cache.

PS Firestore storage initialization and corresponding logs, sorry not 500ms but 350, it's different, sometimes 400, sometimes 300:

  public FirestoreStorage(String userRef) {
    Log.i(TAG, "User ref: \"" + userRef + "\"");
    db = FirebaseFirestore.getInstance();
    Log.i(TAG, "Is persistence enabled: " + db.getFirestoreSettings().isPersistenceEnabled());
    DocumentReference userDoc = db.collection("users").document(userRef);
    prefsCollection = userDoc.collection("prefs");
    prefsCollection.addSnapshotListener(
        Executors.newFixedThreadPool(2),
        new EventListener<QuerySnapshot>() {
          @Override
          public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
            Log.d(TAG, "Prefs.onEvent");
         }
    });
    Log.i(TAG, "Snapshot listener added");

    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

Logs:

10-11 23:11:42.382 I/FirestoreStorage: User ref: "<cut>"
10-11 23:11:42.474 I/FirestoreStorage: Is persistence enabled: true
10-11 23:11:42.496 I/FirestoreStorage: Snapshot listener added
10-11 23:11:42.855 D/FirestoreStorage: Prefs.onEvent
like image 832
smok Avatar asked Oct 10 '17 20:10

smok


People also ask

How do I get data from a firestore document?

To read a single document, we can use DocumentReference's get() method that returns a Task<DocumentSnapshot>, while reading multiple documents from a collection or Query, we can use Firestore Query's get() method that returns an object of type Task<QuerySnapshot>. Both methods read the data only once.

Why are my firestore reads so high?

If you leave the console open on a collection or document with busy write activity then the Firebase console will automatically read the changes that update the console's display. Most of the time this is the reason for unexpected high reads.

Is firestore faster than Realtime Database?

Cloud Firestore also features richer, faster queries and scales further than the Realtime Database. Realtime Database is Firebase's original database. It's an efficient, low-latency solution for mobile apps that require synced states across clients in realtime.


1 Answers

These get() requests are reading the data from the Cloud Firestore backend, over the network, so they'll necessarily be much slower than SQLite which is just reading locally from disk. The first read is also likely to be slower than subsequent ones since it has to initiate the network channel to the backend. We'll look at improving performance over time, but you can't expect 0 ms if you're retrieving data over the network.

You may want to enable offline persistence which would enable local caching of data you've previously read. Note though that get() calls will still try to hit the network first to give you as up-to-date data as possible. If you use addSnapshotListener() instead, we'll call you immediately with the cached data, without waiting for the network.

like image 89
Michael Lehenbauer Avatar answered Oct 04 '22 18:10

Michael Lehenbauer