-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: 독서태그 N+1문제를 해결합니다. #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -102,8 +102,36 @@ class ReadingRecordDomainService( | |||||||||||||||||||||||||||||||||||||||||
| sort: ReadingRecordSortType?, | ||||||||||||||||||||||||||||||||||||||||||
| pageable: Pageable | ||||||||||||||||||||||||||||||||||||||||||
| ): Page<ReadingRecordInfoVO> { | ||||||||||||||||||||||||||||||||||||||||||
| return readingRecordRepository.findReadingRecordsByDynamicCondition(userBookId, sort, pageable) | ||||||||||||||||||||||||||||||||||||||||||
| .map { buildReadingRecordInfoVO(it) } | ||||||||||||||||||||||||||||||||||||||||||
| val readingRecordPage = readingRecordRepository.findReadingRecordsByDynamicCondition(userBookId, sort, pageable) | ||||||||||||||||||||||||||||||||||||||||||
| if (readingRecordPage.isEmpty) { | ||||||||||||||||||||||||||||||||||||||||||
| return Page.empty(pageable) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| val readingRecords = readingRecordPage.content | ||||||||||||||||||||||||||||||||||||||||||
| val readingRecordIds = readingRecords.map { it.id.value } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| val readingRecordTags = readingRecordTagRepository.findByReadingRecordIdIn(readingRecordIds) | ||||||||||||||||||||||||||||||||||||||||||
| val tagIds = readingRecordTags.map { it.tagId.value } | ||||||||||||||||||||||||||||||||||||||||||
| val tagsById = tagRepository.findByIds(tagIds).associateBy { it.id.value } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| val tagsByReadingRecordId = readingRecordTags | ||||||||||||||||||||||||||||||||||||||||||
| .groupBy { it.readingRecordId.value } | ||||||||||||||||||||||||||||||||||||||||||
| .mapValues { (_, tags) -> | ||||||||||||||||||||||||||||||||||||||||||
| tags.mapNotNull { tagsById[it.tagId.value] } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+117
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 가독성 니트픽: 람다 변수명 충돌 방지
- val tagsByReadingRecordId = readingRecordTags
- .groupBy { it.readingRecordId.value }
- .mapValues { (_, tags) ->
- tags.mapNotNull { tagsById[it.tagId.value] }
- }
+ val tagsByReadingRecordId = readingRecordTags
+ .groupBy { it.readingRecordId.value }
+ .mapValues { (_, tagLinks) ->
+ tagLinks.mapNotNull { tagsById[it.tagId.value] }
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| val userBook = userBookRepository.findById(userBookId) | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return readingRecordPage.map { readingRecord -> | ||||||||||||||||||||||||||||||||||||||||||
| ReadingRecordInfoVO.newInstance( | ||||||||||||||||||||||||||||||||||||||||||
| readingRecord = readingRecord, | ||||||||||||||||||||||||||||||||||||||||||
| emotionTags = tagsByReadingRecordId[readingRecord.id.value]?.map { it.name } ?: emptyList(), | ||||||||||||||||||||||||||||||||||||||||||
| bookTitle = userBook?.title, | ||||||||||||||||||||||||||||||||||||||||||
| bookPublisher = userBook?.publisher, | ||||||||||||||||||||||||||||||||||||||||||
| bookCoverImageUrl = userBook?.coverImageUrl, | ||||||||||||||||||||||||||||||||||||||||||
| author = userBook?.author | ||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+125
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 제네릭 추론 보조(필요 시만): 람다 파라미터 타입 명시 환경에 따라 드물게 - return readingRecordPage.map { readingRecord ->
+ return readingRecordPage.map { readingRecord: ReadingRecord ->
ReadingRecordInfoVO.newInstance(
readingRecord = readingRecord,
emotionTags = tagsByReadingRecordId[readingRecord.id.value]?.map { it.name } ?: emptyList(),
bookTitle = userBook?.title,
bookPublisher = userBook?.publisher,
bookCoverImageUrl = userBook?.coverImageUrl,
author = userBook?.author
)
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| fun modifyReadingRecord( | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import java.util.UUID | |
| interface ReadingRecordTagRepository { | ||
| fun saveAll(readingRecordTags: List<ReadingRecordTag>): List<ReadingRecordTag> | ||
| fun findByReadingRecordId(readingRecordId: UUID): List<ReadingRecordTag> | ||
| fun findByReadingRecordIdIn(readingRecordIds: List<UUID>): List<ReadingRecordTag> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 배치 조회 메서드 추가는 방향 OK. 입력/결과 계약을 명시해 주세요. 빈 리스트 입력 시 반환 값(빈 리스트 권장), 중복 ID 처리, 결과 정렬 보장 여부를 KDoc에 명확히 남겨주세요. 서비스/인프라에서 이미 안전 가드를 둘 예정이라도 계약을 확실히 해두면 유지보수 비용이 줄어듭니다. 🤖 Prompt for AI Agents |
||
| fun deleteAllByReadingRecordId(readingRecordId: UUID) | ||
| fun countTagsByUserIdAndUserBookIdAndCategories(userId: UUID, userBookId: UUID, categories: List<String>): Map<String, Int> | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,5 +6,6 @@ import java.util.* | |
|
|
||
| interface JpaReadingRecordTagRepository : JpaRepository<ReadingRecordTagEntity, UUID>, JpaReadingRecordTagQuerydslRepository { | ||
| fun findByReadingRecordId(readingRecordId: UUID): List<ReadingRecordTagEntity> | ||
| fun findByReadingRecordIdIn(readingRecordIds: List<UUID>): List<ReadingRecordTagEntity> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 빈 컬렉션 IN 처리 주의. Spring Data JPA에서 🤖 Prompt for AI Agents |
||
| fun deleteAllByReadingRecordId(readingRecordId: UUID) | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,7 +20,18 @@ class ReadingRecordTagRepositoryImpl( | |||||||||||||||||||||||||||||||||
| return jpaReadingRecordTagRepository.findByReadingRecordId(readingRecordId).map { it.toDomain() } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| override fun countTagsByUserIdAndUserBookIdAndCategories(userId: UUID, userBookId: UUID, categories: List<String>): Map<String, Int> { | ||||||||||||||||||||||||||||||||||
| override fun findByReadingRecordIdIn(readingRecordIds: List<UUID>): List<ReadingRecordTag> { | ||||||||||||||||||||||||||||||||||
| if (readingRecordIds.isEmpty()) return emptyList() | ||||||||||||||||||||||||||||||||||
| return jpaReadingRecordTagRepository | ||||||||||||||||||||||||||||||||||
| .findByReadingRecordIdIn(readingRecordIds) | ||||||||||||||||||||||||||||||||||
| .map { it.toDomain() } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+23
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) 대규모 IN 파라미터 대비: 중복 제거 + 청크 처리 제안 대량 ID 입력 시 DB 바인드 한도/플랜 비대화 대비를 권장합니다. 안전하게 - override fun findByReadingRecordIdIn(readingRecordIds: List<UUID>): List<ReadingRecordTag> {
- if (readingRecordIds.isEmpty()) return emptyList()
- return jpaReadingRecordTagRepository
- .findByReadingRecordIdIn(readingRecordIds)
- .map { it.toDomain() }
- }
+ override fun findByReadingRecordIdIn(readingRecordIds: List<UUID>): List<ReadingRecordTag> {
+ if (readingRecordIds.isEmpty()) return emptyList()
+ return readingRecordIds
+ .distinct()
+ .chunked(1_000)
+ .flatMap { chunk ->
+ jpaReadingRecordTagRepository.findByReadingRecordIdIn(chunk)
+ }
+ .map { it.toDomain() }
+ }📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| override fun countTagsByUserIdAndUserBookIdAndCategories( | ||||||||||||||||||||||||||||||||||
| userId: UUID, | ||||||||||||||||||||||||||||||||||
| userBookId: UUID, | ||||||||||||||||||||||||||||||||||
| categories: List<String> | ||||||||||||||||||||||||||||||||||
| ): Map<String, Int> { | ||||||||||||||||||||||||||||||||||
| return jpaReadingRecordTagRepository.countTagsByUserIdAndUserBookIdAndCategories(userId, userBookId, categories) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
빈 태그일 때 DB 호출 방지 + 중복 tagIds 제거
태그가 없으면
findByIds를 건너뛰고, 중복 tagId를 제거해 바인딩 수를 줄이세요.📝 Committable suggestion
🤖 Prompt for AI Agents