With Room if there is any change to any tables that are in the query, that will trigger the query to run again. There is absolutely no way around that. When a table changes, Room cannot itself understand what that means for the results of any particular query (where clauses, ordering, grouping, etc). It just has to run the query again.
If you use PagingSource Room will only load a batch of entities (I think around 50 at a time by default) according to where the user has scrolled to. This makes things more efficient. Once those objects come to compose, compose will spot when things haven't changed, and it won't bother re-rendering those that have not changed.
A few things to look out for:
1. Make sure you query is efficient Use indexes where needed, or make a cached results table if you need to.
2. When making changes to the database, use a transaction. One transaction will trigger the invalidation once (even if there are many changes within the same transaction). If you make n changes without a transaction, you will trigger the invalidation n times.
3. If needed, you can wrap the pagingsource to intercept the invalidation call to add a delay, thus limiting how often it's triggered.
Most SQLite queries to fetch 50 rows or so shouldn't take longer than a 10 milliseconds or so. You can test queries using SQLiteBrowser if you need to.
I think if you use the default pagingsource from Room the user's scroll position should remain the same.