dexie / Dexie.js

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

bulkGet is much slower then bulkPut #1756

Open muhamedkarajic opened 1 year ago

muhamedkarajic commented 1 year ago

In general write should always be slower then read? How it comes that the bulkGet function is performing much much slower then the bulkPut. I have e.g. 1000 objects when I want to simply put them into the database it takes like 0.01s, however when I want to load them it takes around 0.8s.

Probably people are wondering why I'm asking this cause its about milliseconds, however we are working on a generic storage and every millisecond has a significant impact.

E.g. if I would be using in my code base instead of for of the classic .forEach function I would add seconds to the hole execution of the app.

Therefor I'm interested if I'm doing anything wrong, cause dexie claims their get function should be working blazing fast.

BulkGet code:

cachedEntitys = await clientStorage.entities.bulkGet(['guid-1', 'guid-2']);

BulkPut code:

await clientStorage.entities.bulkPut([{id: 'guid-1'}, {id: 'guid-2'}]);

Am I maybe doing something wrong when defining the store configuration?

const objectStorage = new Dexie('store') as IObjectStorage;

objectStorage.version(1).stores({
    [nameof<IObjectStorage>('objects')]: 'id',
});

await objectStorage.open();

The reads and the writes happen after each other and there is a significant time space between each.

Please let me know if this behavior is normal cause I would expect the library to handle reads much better then writes. Bdw this isn't anything to blame about the library it works significantly better then any other we tried out. Thank you for the hard work its appreciated.

From looking at the code everything seems fine, its either indexeddb performance itself or there is something which is not so obvious.

I wonder if someone can investigate the functions: function mutate ({trans, type, keys, values, range}) and getMany ({trans, keys})

muhamedkarajic commented 1 year ago

If I'm correct the underlaying issue is that indexeddb can't do a get for many records, it only allows you to fetch either everything or one by one. So there is no alternative then to use the option to fetch one by one and by the put/add/delete you can use the bulk cause it allows you to do so.

When using the 'where' it loads everything to memory first and then executes the filtering logic I guess?

image
dfahlander commented 1 year ago

It could matter how the measurements are being made. It could also be that the writes are fast to add them to the "oplog" but the underlying database engine need to do more work after the write before the reads starts getting faster. I haven't measured bulkGet performance but I would suggest to do the same bulkGet twice or more after bulkPut is complete to see whether the second time bulkGet is done would be faster (to be certain dexie doesn't return any results from cache, create the dexie instance with { cache: 'disabled' } option so that the real IndexedDB get times are being measured.

Also, make sure the bulkGet request doesn't involve an implicit call to db.open() (but it seems you are doing an explicit open, so I suppose not).

muhamedkarajic commented 1 year ago

Also, make sure the bulkGet request doesn't involve an implicit call to db.open() (but it seems you are doing an explicit open, so I suppose not).

I'm opening the database once when the app starts, I didn't had so far any issues. I wonder if there are pro/contras to that approach?