-
Notifications
You must be signed in to change notification settings - Fork 18
Bulk read/write API #63
Comments
This discussion is a bit split across here and #57 (comment), but I'll repeat from there that the main tradeoff for adding new features is ensuring that they benefit real-world apps. It's very clear that KV storage, being only a subset of IndexedDB by design, is less capable and doesn't have bulk operations at this time. The question is, how much of a problem is that for real-world apps? Are there real-world apps that want to perform simple key-value storage operations, but also perform them so often and in such volume, that the current API causes noticeable user-facing slowdowns? Our conjecture was that apps that need that kind of transaction volume would rather use IndexedDB directly, or would face that transaction volume in rare-enough instances that dropping down and using the But we might be wrong! Do you have a site that's using, e.g., a different IndexedDB wrapper library today, and wants to move to KV storage but can't because that'd cause user-noticeable performance problems from de-batching? That would be invaluable information for evolving the API, and judging whether increasing the complexity and implementation cost is worth it because of how it makes the web better. I'll also note that it's important to focus on the problem statement, and the solution might not look exactly like changing the web-developer-facing API. For example, in #57 (comment) Firefox developers suggest that one path forward might be took the same web-dev-facing API, but optimize it so that it operates "as fast as" batch operations. But, all that talk is premature without having some examples of actual customers (not synthetic benchmarks) who would benefit from such an upgrade. |
The synthetic benchmark above is just an extract of what an app is doing on update, actually reduced since the original could take more than 2 seconds. As the experience shows (Best Practices for Using IndexedDB), instead of storing a huge state object as a single entry apps should break it down into small atomic things. While one could argue such activities are rare, but it doesn't mean the users should wait for seconds instead of milliseconds. Even the much more primitive WebExtensions/chrome-extensions API provides a way to perform bulk operations. |
Ah, great! Could you point me to the app? |
It's a chrome extension I'm playing with - a 4k array of rule objects (built from a json on update) should be loaded each time the background script resumes after being unloaded - that is almost on every tab navigation. The array is inside IndexedDB, each rule a separate entry. I'm using getAllKeys to quickly get 4000 urls in just 15ms, find the matching ones, then read the full objects for each one. There must be lots of similar use cases - in advanced [web] apps like editors or games that need to load/save the state. |
Ah, hmm, I see. I'm not sure the web standards process is the best way to add APIs for Chrome extensions; asking Gecko and WebKit to implement something, which would only be used in Chrome, is not great form. Generally, it's best to add Chrome extension APIs through the Chrome extension API process, not the web platform standards process. Still, I believe you that it's possible there's web apps that might benefit from this. Let's keep this open to track the feature request, in the hopes of finding a web app to work with on this sort of feature addition with us. Maybe one useful thing to ask, is are there other parts of the IndexedDB API you are using (e.g. indices, transactions, multiple separate object stores, ...), or are you just using it as a key/value store? |
The features of IndexedDB I'm using aren't specific to extensions API so it's not pertinent to the message I was trying to convey: I believe there are lots of web apps that [will] need to perform bulk operations. I've mentioned the set/get methods of extensions API just to show a possible way to expose the putMany/getMany functionality.
I'm using an additional index indeed and a second store, although it's not crucial - just a minor touch. |
The current kv-storage API doesn't provide a way to read/write multiple values in one transaction so it's ultraslow when working with a lot of values. This is a known problem of IndexedDB design. We have to perform all the individual operations inside one IndexedDB transaction's IDBObjectStore (or IDBIndex) and resolve the outer Promise in the last IDBRequest. For example, in Chrome the difference could be 2000ms of separate transactions for each
put
vs 200ms of a single transaction with manyput
inside when reading/enumerating/writing a few thousand of simple objects. HTML5 localStorage would be even faster, close to 20ms.Even the intentionally primitive storage API of WebExtensions/chrome-extensions has
set({key1: obj1, key2: obj2})
to create a separate record for each key:value pair andget(['key1', 'key2'])
orget({key1: default1, key2: default2})
to read separate keys in one fast internal operation.It should be noted that enumerating of keys/values based on IndexedDB cursor is also 10 times slower at least in Chrome due to running each internal onsuccess callback in a separate task of the event loop. So in addition to
keys()
,values()
, andentries()
it would make sense to exposeallKeys()
,allValues()
, that correspond to IndexedDB's getAllKeys, getAll. As forallEntries()
it doesn't have a single-op implementation but it might make sense to perform getAllKeys + getAll and combine the result.While the simplicity of the API is important, but my point is, without these optimized methods kv-storage is somewhat of a toy for really simple cases that can't replace neither IndexedDB nor even HTML5 localStorage where low-latency high-efficiency processing of many entries is required.
kv-storage with 1k records: 750ms + 250ms
IndexedDB bulk ops with 1k records: 55ms + 80ms (3-13 times faster) and 10-40ms for getAllKeys+getAll
HTML localStorage with 1k records: 10ms + 5ms (50-75 times faster)
The text was updated successfully, but these errors were encountered: