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
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With