-
Notifications
You must be signed in to change notification settings - Fork 1
feat: 경매장 거래 내역 기본 조회 시 인덱스 사용을 위한 쿼리 수정 #88
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 |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| package until.the.eternity.auctionhistory.domain.service.fetcher; | ||
|
|
||
| import java.util.List; | ||
| import until.the.eternity.auctionhistory.interfaces.external.dto.OpenApiAuctionHistoryResponse; | ||
| import until.the.eternity.common.enums.ItemCategory; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface AuctionHistoryFetcherPort { | ||
| List<OpenApiAuctionHistoryResponse> fetch(ItemCategory category); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,11 +8,6 @@ | |
| import com.querydsl.core.types.dsl.NumberTemplate; | ||
| import com.querydsl.jpa.JPAExpressions; | ||
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||
| import java.time.Instant; | ||
| import java.time.LocalDate; | ||
| import java.time.ZoneId; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.data.domain.Page; | ||
| import org.springframework.data.domain.PageImpl; | ||
|
|
@@ -28,6 +23,12 @@ | |
| import until.the.eternity.auctionhistory.interfaces.rest.dto.request.PriceSearchRequest; | ||
| import until.the.eternity.auctionitemoption.domain.entity.QAuctionItemOption; | ||
|
|
||
| import java.time.Instant; | ||
| import java.time.LocalDate; | ||
| import java.time.ZoneId; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| class AuctionHistoryQueryDslRepository { | ||
|
|
@@ -71,17 +72,32 @@ public Page<AuctionHistory> search(AuctionHistorySearchRequest condition, Pageab | |
| // 3단계: 정렬 조건 빌드 | ||
| List<OrderSpecifier<?>> orderSpecifiers = buildOrderSpecifiers(pageable, ah); | ||
|
|
||
| // 4단계: 모든 옵션과 함께 조회 (LEFT JOIN - 조건 없음!) | ||
| // 4단계: Deferred Join (Late Row Lookup) 패턴 적용 | ||
| // 4-1단계: ID만 먼저 조회 (인덱스 활용) | ||
| List<String> ids = | ||
| queryFactory | ||
| .select(ah.auctionBuyId) | ||
| .from(ah) | ||
| .where(historyBuilder) | ||
| .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) | ||
| .offset(pageable.getOffset()) | ||
| .limit(pageable.getPageSize()) | ||
| .fetch(); | ||
|
|
||
| // 결과가 없으면 빈 페이지 반환 | ||
| if (ids.isEmpty()) { | ||
| return new PageImpl<>(List.of(), pageable, 0L); | ||
| } | ||
|
|
||
| // 4-2단계: ID로 상세 조회 (LEFT JOIN으로 옵션 포함) | ||
| List<AuctionHistory> content = | ||
| queryFactory | ||
| .selectFrom(ah) | ||
| .leftJoin(ah.auctionItemOptions, aio) | ||
| .fetchJoin() | ||
| .where(historyBuilder) | ||
| .where(ah.auctionBuyId.in(ids)) | ||
| .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) | ||
| .distinct() // 중복 제거 | ||
| .offset(pageable.getOffset()) | ||
| .limit(pageable.getPageSize()) | ||
| .distinct() | ||
| .fetch(); | ||
|
Comment on lines
+92
to
101
|
||
|
|
||
| // Count 쿼리 (JOIN 없이 실행) | ||
|
|
||
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.
The deferred join pattern optimization lacks documentation explaining why this approach is used and what performance benefits it provides. Consider adding a comment block before step 4 that explains: 1) The purpose of the two-step query (Late Row Lookup pattern), 2) The performance benefit of fetching IDs first with index-only scan, 3) Any trade-offs or limitations of this approach.