Skip to content
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

[BE] refactor: 상품 목록 조회 api 성능 개선 #685

Merged
merged 20 commits into from
Oct 17, 2023

Conversation

hanueleee
Copy link
Collaborator

@hanueleee hanueleee commented Sep 20, 2023

Issue

✨ 구현한 기능

상품 목록 조회 Api 성능 개선

(기존)

  • ReviewCount를 위해 Product와 Review Join
  • Page반환
  • reviewCount 기준 정렬로 인해 service에 분기 + repository에 메소드 2개

(1차 개선)

  • ReviewCount 반정규화
  • Page 대신 Slice 반환
    • 펀잇은 무한스크롤 방식이기 때문에 페이징에 대한 자세한 정보(ex. 총 페이지 수)가 필요없다.
    • Slice를 반환하여 hasNext(다음 페이지가 존재하는지)값만 넘기도록 수정
  • 오프셋 페이징 -> 커서 페이징
SELECT
    p.id,
    p.name,
    p.price,
    p.image,
    p.average_rating,
    p.review_count
FROM product p
JOIN product p2
    ON p2.id = :lastProductId
WHERE
        p.category_id = 2 AND
        (
            (p.price = p2.price AND p.id < :lastProductId) OR
            p.price > p2.price
        )
ORDER BY p.price, p.id DESC
LIMIT 11;

(2차 개선) 인덱스

(3차 개선) 동적 쿼리 ???

📢 논의하고 싶은 내용

Pageable을 걷어내다보니 정렬조건에 따라 메소드가 무려 10개가 나옵니다.
동적쿼리를 위한 QueryDsl 도입이 시급!

🎸 기타

  • X

⏰ 일정

  • 추정 시간 :
  • 걸린 시간 :

@hanueleee hanueleee self-assigned this Sep 20, 2023
@github-actions
Copy link

github-actions bot commented Sep 20, 2023

Test Results

258 tests   258 ✔️  20s ⏱️
130 suites      0 💤
130 files        0

Results for commit 9d9008a.

♻️ This comment has been updated with latest results.

@hanueleee
Copy link
Collaborator Author

hanueleee commented Oct 10, 2023

3-1 동적 쿼리 사용 X

service
image
repository
image

@hanueleee hanueleee changed the title [BE] 상품 목록 조회 api 성능 개선 [BE] refactor : 상품 목록 조회 api 성능 개선 Oct 12, 2023
@hanueleee hanueleee changed the title [BE] refactor : 상품 목록 조회 api 성능 개선 [BE] refactor: 상품 목록 조회 api 성능 개선 Oct 12, 2023
@hanueleee
Copy link
Collaborator Author

hanueleee commented Oct 15, 2023

3-2 동적 쿼리 사용 (criteria + specification)

고민 과정

  1. join
SELECT
    p.id, p.name, p.price, p.image, p.average_rating, p.review_count
FROM product p
JOIN product p2
    ON p2.id = :lastProductId
WHERE
        p.category_id = 2 AND
        (
            (p.price = p2.price AND p.id < :lastProductId) OR
            p.price > p2.price
        )
ORDER BY p.price, p.id DESC
LIMIT 11;

위와 같은 기존 쿼리를 살려서 join을 하고자 했으나,
p(product)와 p2(product) 사이의 연관관계가 없어서 specification을 통해 쿼리를 만들 수가 없었습니다.
specification에서 join을 사용하려면 엔티티간 연관관계가 존재해야함!! (엔티티 클래스에 매핑 추가)

  1. subquery
SELECT
    p.id, p.name, p.price, p.image, p.average_rating, p.review_count
FROM product p
WHERE
        p.category_id = 2 AND
        (
            (p.price = (select price from product where id = :lastProductId) AND p.id < :lastProductId)
            OR p.price > (select price from product where id = :lastProductId)
        )
ORDER BY p.price, p.id DESC
LIMIT 11;

1)에서 Join을 하는 이유가 lastProduct의 price가 필요해서 였기 때문에,
subquery로도 해결은 가능합니다.
하지만 서브쿼리는 성능상 좋지않고 완전히 동일한 서브쿼리가 2번 나간다는 점에서 탈락!

  1. findById로 price 가져오기

위 모든 행위의 이유는 딱 'lastProduct의 price가 필요'해서 -> 그냥 findById로 가져오는 건 어떨까?
우리가 사용하는 db는 mysql이고 innoDB이기 때문에 PK 기반 조회는 매우 빠를 것.
그러므로 일단 이 방법을 사용하기로 결정!
(전에 다같이 잠깐 논의했던대로 프론트에서 price를 넘겨주게 된다면 해당 로직 제거 가능)

결과

service
image

관련 커밋

@hanueleee
Copy link
Collaborator Author

hanueleee commented Oct 15, 2023

3-3 API 개선 (count 쿼리 제거)

specification을 사용할 때에는 보통 JpaSpecificationExecutor를 쓴다.
image
3-2에는 페이징(limt)을 위해 pageable이 필요하기 때문에 저 3번째를 사용했었다.

Page를 반환값으로 하면 count쿼리가 계속 나감
-> 펀잇은 무한스크롤 방식이기 때문에 페이징에 대한 자세한 정보(ex. 총 페이지 수)가 필요없다
-> 반환값을 List로 하고 싶다

커스텀 레포지토리(BaseRepository)에 specification용 메소드 추가

  • 기존에 pageable은 오직 limit을 위해 사용했었음 -> pageable 대신 size를 받아와 바로 세팅
  • Page 대신 List를 반환
public List<T> findAllWithSpecification(final Specification spec, final int size) {
        final TypedQuery<T> query = getQuery(spec, Sort.unsorted());
        query.setMaxResults(size);

        return query.getResultList();
    }

관련 커밋

@hanueleee hanueleee requested review from 70825, wugawuga and Go-Jaecheol and removed request for 70825 and wugawuga October 15, 2023 17:53
@hanueleee hanueleee requested a review from wugawuga October 15, 2023 17:54
Copy link
Collaborator

@wugawuga wugawuga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다!

Copy link
Member

@70825 70825 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

간단한 것만 수정하면 될 것 같아요~
고생하셨습니다~

Copy link
Collaborator

@Go-Jaecheol Go-Jaecheol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코멘트 몇 개 남겨두었습니다.
확인해주세요~~!~!

Copy link
Collaborator

@Go-Jaecheol Go-Jaecheol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨어요~~

@hanueleee hanueleee merged commit 0cddbdf into develop Oct 17, 2023
3 checks passed
@hanueleee hanueleee deleted the feat/issue-669 branch October 17, 2023 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BE] 상품목록조회api 수정 및 개선
4 participants