dexie / Dexie.js

A Minimalistic Wrapper for IndexedDB
https://dexie.org
Apache License 2.0
11.69k stars 641 forks source link

Performance comparision between Dexie and Browser's IndexedDB API #1613

Open anurasin opened 2 years ago

anurasin commented 2 years ago

I was compairing the get from store performance between Dexie and Indexed DB API.

I have created two test HTML pages (attached) 1.) with Dexie and 2) with Browser indexed DB API, and have tried for multiple scenarios with different DB sizes (in terms of a number of entries in the DB) vs the Number of parallel Indexed DB get calls.

Following are my observations: (on Edge) image

IndexedDB APIs surely are the clear winner here over Dexie with a huge margin.

I am not sure if I have missed something in the usage of Dexie to harness its full potential but clearly it seems like for large number of parallel get calls Dexie regresses much faster than IndexedDB APIs in the latency.

Let me know if I am doing something wrong with the usage of Dexie, and by fixing that will make it as performant as IndexedDB APIs. or is Dexie actually slower?

What are others observations?

I am not sure if any issue/discussion is already active or already closed, please point me to that if there is any.

Attaching the zip file with two HTMLs which I used. test_app_indexedDB.zip

tomkennedy22 commented 2 years ago

I can't speak to why the individual transaction performance has such a gap, but are you intentionally not using the Bulk functions? If you build a list of objects to write to the database, and put/add them all at the same time, performance is much better than doing N individual inserts. Same with querying out of the db.

[bulkPut](https://dexie.org/docs/Table/Table.bulkPut()) [bulkGet](https://dexie.org/docs/Table/Table.bulkGet())

anurasin commented 2 years ago

Apologies If I have missed mentioning it somewhere, these numbers are of readonly transaction, not readwrite.

dfahlander commented 2 years ago

@anurasin The tests are not comparable as the native-indexedDB version runs them in a single transaction and the dexie-based test in your zip does not create a transaction but runs every request in its own implicit transaction.

To make a comparable test, one must do this within a single transaction in both tests.

I hope to get some time to create a performance test that compares dexie performance with native IDB using transactions or bulk methods(as @tomkennedy22 also mentions).

For a start, run your loop within a dexie transaction. I'll be glad to follow up on it.

anurasin commented 2 years ago

@dfahlander thank you for replying. In my scenario, I need to create transactions for each read request. So to compare I will share the perf numbers of updated Native IDB with each read request within a separate transaction.
Though, I remember vaguely that I tried that already and didn't see much change in the numbers. I will re-run the native IDB test and share the new perf numbers anyways.

I cannot use bulkGet and bulkPut in my scenario, I have to make several independent read calls.

anurasin commented 2 years ago

Following are the perf number for Native IDB when each read request is wrapped within a separate transaction.

The numbers do not change that much, the performance of native IDB is better than Dexie for the same scenario (number of parallel transactions).

image

@dfahlander please suggest what can I do to make my Dexie code comparable to that of native IDB in terms of performance.

dfahlander commented 2 years ago

I dived into your tests again and found one big and very important difference in what is being measured. The native IDB requests does a simple IDBObjectStore.get(primaryKey), while the dexie tests does case insensitive searches ([equalsIgnoreCase()](https://dexie.org/docs/WhereClause/WhereClause.equalsIgnoreCase())) on an index, returning more results and requiring a lot more advanced logic than a simple get(). They also operate on different databases with different structures.

I tried to modify your tests to perform the exact same operations. As there's no such thing as case insensitive search in native IndexedDB, I choosed to do simple get() request on for both tests. I still see that dexie's Table.get() is not equally fast as native IDBObjectStore.get(), but the difference is not of that magnitude as was presented in your results.

This is what I get on my macbook 2,2 GHz Quad-Core Intel Core i7 when running on Chrome Version 105.0.5195.125 (Official Build) (x86_64). They were of course started without devtools open, and then, I opened devtools when page was loaded, to collect the results:

idb type db entries 1 parallel 100 parallel 1000 parallel
native idb 1000 1.3 32 278
dexie 1000 2 43 391
dexie single tx 1000 1.9 34.4 298
dexie bulkGet 1000 1.8 25.3 197.5
native idb single tx 1000 1.1 28.4 238.9
native idb w/o log 1000 1.2 26.5 200

So, still Dexie is slightly slower than the native IDB on simple get operations. One interesting result is that Dexie's bulkGet() seems to actually be faster than the native test. That is probably just luck (each run revelas slightly different results) and possible that dexie'd bulkGet() don't do anything else than collect results, while the test had some calls to performance.now() and console.log in every iteration. After removing those I get similar results btwn native IDB and Dexie bulkGet() (see row native idb w/o log).

Conclusion so far:

We haven't measured range-based queries or index based queries yet. I would assume we get a more similar result between native IDB and Dexie queries then, as they put more burden into the IndexedDB engine and less burden on the JS code.

test_app_indexedDB2.zip