PhongBM
06/29/2023, 9:39 AMs = System.currentTimeMillis()
invoiceIds.map {
async {
val t = System.currentTimeMillis()
val invoice = invoiceDao.findById(it.webId)
Log.d(TAG, "${System.currentTimeMillis() - t} ms")
invoice
}
}.awaitAll()
Log.d(TAG, "Total ${System.currentTimeMillis() - s} ms")
What is the cause and is there a way to fix it?
Thanks in advance!Brian Cooley
06/29/2023, 9:53 PMinvoiceDao
interface, you could add a method that takes a list of whatever type webId
is. For example, the following might do the trick:
@Query("SELECT * FROM invoices WHERE webId IN (:webIds)")
fun findByIds(webIds: List<Int>): List<Invoice>
Then you could map
the invoiceIds
to a list of webIds
and make a single call to invoiceDao.findByIds(webIds)
. As a bonus you'd get to drop the awaitAll()
call since it is just one query.
See https://developer.android.com/training/data-storage/room/accessing-data#collection-parameters for a reference.
Here's a Stack Overflow question that discusses the relative performance, but YMMV and you'll want to test for yourself: https://stackoverflow.com/questions/5803472/sql-where-id-in-id1-id2-idn
Finally, just wanted to mention that Kotlin has a convenient measureTimeMillis
that can ease the pain of timing method calls. No more need to repeatedly call System.currentTimeMillis()
! See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.system/measure-time-millis.html
Good luck and happy coding!PhongBM
06/30/2023, 1:14 AMBrian Cooley
06/30/2023, 1:16 PMDoes Room support concurrent queries with better performance?Room is just an abstraction layer over SQLite, so you are bound to the concurrency characteristics of SQLite. I don't know that much about concurrency in a SQLite database. My understanding is that reads are concurrent but writes are sequential. And reads lock out writes. Write-ahead logging and transactions are usually what is recommended to improve performance. I think WAL is on by default in Room. I don't have much guidance to offer regarding transactions. From a Kotlin coroutine perspective, it's always good to keep in mind that 1 coroutine != 1 thread. Each dispatcher is backed by a different thread pool. For database queries, I use
<http://Dispatchers.IO|Dispatchers.IO>
which is designed for blocking operations and uses a larger thread pool, I think it is 64 threads. Dispatchers.Default
thread pool is the number of cores on the device IIRC, and Dispatchers.Main
will be just 1 thread, the main thread.