seigel / pouchdb-react-native

Pouchdb with async storage
MIT License
484 stars 68 forks source link

iOS Performance Considerations - Read Before Using #118

Open cjroth opened 5 years ago

cjroth commented 5 years ago

Hello!

First off, thank you for this adapter!

I've been trialing a few mobile syncing options and different PouchDB adapters in the past few months and this was my pick until I realized there are some severe performance and memory issues on iOS.

Overall Memory

I've been experimenting with a database of 5k documents (~10 revisions), totally ~7MB, and syncing this with a CouchDB cluster and it takes quite a bit of memory compared with pouchdb-adapter-react-native-sqlite. To test this I created a clean React Native project and then synced my 5k document database. The app took about 130MB on average (in both Release and Debug mode) when using the AsyncStorage adapter vs about 45MB with the Sqlite adapter. This is a pretty severe difference.

Memory when there is other data in AsyncStorage (not related to current database)

I found that the database became increasingly slow and consumed increasing amounts of memory due to it reading ALL AsyncStorage keys from disk, even those not related to the current database. I'm using multiple databases, so this was very noticeable for me. This is not a problem with the Sqlite adapter. I will say this below again, but this is not really the fault of this adapter, it is more of a problem with how AsyncStorage's local storage implementation works on iOS. There IS a solution, if you MUST use AsyncStorage: use AsyncStorage backed by RocksDB which provides a getAllKeysWithPrefix, allowing the current database to be unaffected by other AsyncStorage data. I've created a PR to get this working with this adapter.

Slow read times

Additionally, there are performance concerns with timing. I found that the Sqlite adapter could resolve allDocs({ include_docs: true }) in about 450ms whereas AsyncStorage generally took around 8-12 seconds. I found bulkDocs and generally all of the operations to be similarly slow, even with start_key and end_key specified. They do get a bit faster when building for Release, but not faster enough to make up for the difference between this and Sqlite. Do note that the Sqlite adapter is a bit slower at writes.

TLDR

Basically, AsyncStorage on iOS is hella slow and memory inefficient and gets even worse in proportion to the amount of data you are using. Be sure to take these into consideration before using this adapter.

Again, I do not believe the performance issues with pouchdb-react-native have much to do with the adapter itself. They are mostly related to React Native's AsyncStorage and thus out of the control of this adapter. Unless the React Native team improves the performance of AsyncStorage or adds support for IndexedDB, I would recommend considering pouchdb-adapter-react-native-sqlite instead.

greenais commented 5 years ago

Thank you for such a great research! Chapeau.

mqtik commented 3 years ago

Yeah.

For starters, you might want to (no, need to) drop AsyncStorage and use LevelDB: https://github.com/greentriangle/react-native-leveldb

On the other hand, it shouldn´t iterate with all documents for doing queries. That´s the memory killer. But even with that, it wouldn´t perform like SQLite.

However, LevelDB does perform a lot better than SQLite.

If some of you can handle the part of not iterating with all documents when querying (like pouchdb-react native-sqlite does), I´ll happily transition everything to LevelDB.