mirror of
https://github.com/gotson/komga.git
synced 2025-12-16 13:33:49 +01:00
perf: retrieve one to many collections in bulk
This commit is contained in:
parent
5b6c1a56f7
commit
8e9d93f6f9
2 changed files with 71 additions and 49 deletions
|
|
@ -27,12 +27,14 @@ import org.jooq.ResultQuery
|
|||
import org.jooq.impl.DSL
|
||||
import org.jooq.impl.DSL.inline
|
||||
import org.jooq.impl.DSL.noCondition
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.PageImpl
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import java.math.BigDecimal
|
||||
import java.net.URL
|
||||
|
||||
|
|
@ -40,6 +42,8 @@ import java.net.URL
|
|||
class BookDtoDao(
|
||||
private val dsl: DSLContext,
|
||||
private val luceneHelper: LuceneHelper,
|
||||
@Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
) : BookDtoRepository {
|
||||
|
||||
private val b = Tables.BOOK
|
||||
|
|
@ -298,8 +302,30 @@ class BookDtoDao(
|
|||
.apply { if (joinConditions.selectReadListNumber) leftJoin(rlb).on(b.ID.eq(rlb.BOOK_ID)) }
|
||||
.apply { if (joinConditions.author) leftJoin(a).on(b.ID.eq(a.BOOK_ID)) }
|
||||
|
||||
private fun ResultQuery<Record>.fetchAndMap() =
|
||||
fetch()
|
||||
private fun ResultQuery<Record>.fetchAndMap(): MutableList<BookDto> {
|
||||
val records = fetch()
|
||||
val bookIds = records.getValues(b.ID)
|
||||
|
||||
lateinit var authors: Map<String, List<AuthorDto>>
|
||||
lateinit var tags: Map<String, List<String>>
|
||||
lateinit var links: Map<String, List<WebLinkDto>>
|
||||
transactionTemplate.executeWithoutResult {
|
||||
dsl.insertTempStrings(batchSize, bookIds)
|
||||
authors = dsl.selectFrom(a)
|
||||
.where(a.BOOK_ID.`in`(dsl.selectTempStrings()))
|
||||
.filter { it.name != null }
|
||||
.groupBy({ it.bookId }, { AuthorDto(it.name, it.role) })
|
||||
|
||||
tags = dsl.selectFrom(bt)
|
||||
.where(bt.BOOK_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.bookId }, { it.tag })
|
||||
|
||||
links = dsl.selectFrom(bl)
|
||||
.where(bl.BOOK_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.bookId }, { WebLinkDto(it.label, it.url) })
|
||||
}
|
||||
|
||||
return records
|
||||
.map { rec ->
|
||||
val br = rec.into(b)
|
||||
val mr = rec.into(m)
|
||||
|
|
@ -307,25 +333,9 @@ class BookDtoDao(
|
|||
val rr = rec.into(r)
|
||||
val seriesTitle = rec.into(sd.TITLE).component1()
|
||||
|
||||
val authors = dsl.selectFrom(a)
|
||||
.where(a.BOOK_ID.eq(br.id))
|
||||
.fetchInto(a)
|
||||
.filter { it.name != null }
|
||||
.map { AuthorDto(it.name, it.role) }
|
||||
|
||||
val tags = dsl.select(bt.TAG)
|
||||
.from(bt)
|
||||
.where(bt.BOOK_ID.eq(br.id))
|
||||
.fetchSet(bt.TAG)
|
||||
|
||||
val links = dsl.select(bl.LABEL, bl.URL)
|
||||
.from(bl)
|
||||
.where(bl.BOOK_ID.eq(br.id))
|
||||
.fetchInto(bl)
|
||||
.map { WebLinkDto(it.label, it.url) }
|
||||
|
||||
br.toDto(mr.toDto(), dr.toDto(authors, tags, links), if (rr.userId != null) rr.toDto() else null, seriesTitle)
|
||||
br.toDto(mr.toDto(), dr.toDto(authors[br.id].orEmpty(), tags[br.id].orEmpty().toSet(), links[br.id].orEmpty()), if (rr.userId != null) rr.toDto() else null, seriesTitle)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BookSearchWithReadProgress.toCondition(): Condition {
|
||||
var c: Condition = noCondition()
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ import org.jooq.impl.DSL.count
|
|||
import org.jooq.impl.DSL.countDistinct
|
||||
import org.jooq.impl.DSL.lower
|
||||
import org.jooq.impl.DSL.substring
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.PageImpl
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import java.net.URL
|
||||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
|
@ -47,6 +49,8 @@ const val BOOKS_READ_COUNT = "booksReadCount"
|
|||
class SeriesDtoDao(
|
||||
private val dsl: DSLContext,
|
||||
private val luceneHelper: LuceneHelper,
|
||||
@Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int,
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
) : SeriesDtoRepository {
|
||||
|
||||
private val s = Tables.SERIES
|
||||
|
|
@ -216,8 +220,40 @@ class SeriesDtoDao(
|
|||
|
||||
private fun readProgressConditionSeries(userId: String): Condition = rs.USER_ID.eq(userId).or(rs.USER_ID.isNull)
|
||||
|
||||
private fun ResultQuery<Record>.fetchAndMap() =
|
||||
fetch()
|
||||
private fun ResultQuery<Record>.fetchAndMap(): MutableList<SeriesDto> {
|
||||
val records = fetch()
|
||||
val seriesIds = records.getValues(s.ID)
|
||||
|
||||
lateinit var genres: Map<String, List<String>>
|
||||
lateinit var tags: Map<String, List<String>>
|
||||
lateinit var sharingLabels: Map<String, List<String>>
|
||||
lateinit var aggregatedAuthors: Map<String, List<AuthorDto>>
|
||||
lateinit var aggregatedTags: Map<String, List<String>>
|
||||
transactionTemplate.executeWithoutResult {
|
||||
dsl.insertTempStrings(batchSize, seriesIds)
|
||||
genres = dsl.selectFrom(g)
|
||||
.where(g.SERIES_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.seriesId }, { it.genre })
|
||||
|
||||
tags = dsl.selectFrom(st)
|
||||
.where(st.SERIES_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.seriesId }, { it.tag })
|
||||
|
||||
sharingLabels = dsl.selectFrom(sl)
|
||||
.where(sl.SERIES_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.seriesId }, { it.label })
|
||||
|
||||
aggregatedAuthors = dsl.selectFrom(bmaa)
|
||||
.where(bmaa.SERIES_ID.`in`(dsl.selectTempStrings()))
|
||||
.filter { it.name != null }
|
||||
.groupBy({ it.seriesId }, { AuthorDto(it.name, it.role) })
|
||||
|
||||
aggregatedTags = dsl.selectFrom(bmat)
|
||||
.where(bmat.SERIES_ID.`in`(dsl.selectTempStrings()))
|
||||
.groupBy({ it.seriesId }, { it.tag })
|
||||
}
|
||||
|
||||
return records
|
||||
.map { rec ->
|
||||
val sr = rec.into(s)
|
||||
val dr = rec.into(d)
|
||||
|
|
@ -227,40 +263,16 @@ class SeriesDtoDao(
|
|||
val booksInProgressCount = rsr.inProgressCount ?: 0
|
||||
val booksUnreadCount = sr.bookCount - booksReadCount - booksInProgressCount
|
||||
|
||||
val genres = dsl.select(g.GENRE)
|
||||
.from(g)
|
||||
.where(g.SERIES_ID.eq(sr.id))
|
||||
.fetchSet(g.GENRE)
|
||||
|
||||
val tags = dsl.select(st.TAG)
|
||||
.from(st)
|
||||
.where(st.SERIES_ID.eq(sr.id))
|
||||
.fetchSet(st.TAG)
|
||||
|
||||
val sharingLabels = dsl.select(sl.LABEL)
|
||||
.from(sl)
|
||||
.where(sl.SERIES_ID.eq(sr.id))
|
||||
.fetchSet(sl.LABEL)
|
||||
|
||||
val aggregatedAuthors = dsl.selectFrom(bmaa)
|
||||
.where(bmaa.SERIES_ID.eq(sr.id))
|
||||
.fetchInto(bmaa)
|
||||
.filter { it.name != null }
|
||||
.map { AuthorDto(it.name, it.role) }
|
||||
|
||||
val aggregatedTags = dsl.selectFrom(bmat)
|
||||
.where(bmat.SERIES_ID.eq(sr.id))
|
||||
.fetchSet(bmat.TAG)
|
||||
|
||||
sr.toDto(
|
||||
sr.bookCount,
|
||||
booksReadCount,
|
||||
booksUnreadCount,
|
||||
booksInProgressCount,
|
||||
dr.toDto(genres, tags, sharingLabels),
|
||||
bmar.toDto(aggregatedAuthors, aggregatedTags),
|
||||
dr.toDto(genres[sr.id].orEmpty().toSet(), tags[sr.id].orEmpty().toSet(), sharingLabels[sr.id].orEmpty().toSet()),
|
||||
bmar.toDto(aggregatedAuthors[sr.id].orEmpty(), aggregatedTags[sr.id].orEmpty().toSet()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SeriesSearchWithReadProgress.toCondition(): Condition {
|
||||
var c = DSL.noCondition()
|
||||
|
|
|
|||
Loading…
Reference in a new issue