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

모임 리스트 조회 시 페이징 적용 #623

Open
J-I-H-O opened this issue Oct 7, 2024 · 1 comment · May be fixed by #622
Open

모임 리스트 조회 시 페이징 적용 #623

J-I-H-O opened this issue Oct 7, 2024 · 1 comment · May be fixed by #622
Assignees
Labels
🖥 backend backend ✨ feat 기능 개발
Milestone

Comments

@J-I-H-O
Copy link
Contributor

J-I-H-O commented Oct 7, 2024

요구 사항

  • 모임 리스트 조회 시 페이징 적용
@J-I-H-O J-I-H-O added 🖥 backend backend ✨ feat 기능 개발 labels Oct 7, 2024
@J-I-H-O J-I-H-O added this to the Sprint6 milestone Oct 7, 2024
@J-I-H-O J-I-H-O linked a pull request Oct 7, 2024 that will close this issue
@J-I-H-O
Copy link
Contributor Author

J-I-H-O commented Oct 7, 2024

as-is

  • 모임 필터링 조회에 페이징을 적용하면서, 해당 쿼리에서 fetch join을 모두 제거해야 함
    • 하이버네이트는 컬렉션 fetch join과 페이징을 함께 사용하면, 중복 row로 인해 몇 개의 row에 limit를 걸어야할지 판단할 수 없음.
      따라서 메모리로 모두 로딩한 뒤에 엔티티 컬렉션을 pageSize만큼 잘라서 응답함

to-be

  1. join문을 사용하지 않기 위해 서브 쿼리를 최대한 활용해 기존 기능이 그대로 동작하도록 함
    • 이때 ElementalCollection은 엔티티가 존재하지 않기 때문에, join 없이는 조회할 수 없었음
      • ClubGender, ClubSize 를 엔티티로 승격시켜 join 없이 조회할 수 있도록 변경
    • 추가로 critera를 사용하던 기존 코드를 JPQL을 사용하도록 변경
  2. 검색 조건 (province, genders, sizeTypes)은 쿼리에서 거르는게 가능하지만, 필터링 조건 중 하나인 JOINABLE (참여 가능한 모임만 필터링) 은 쿼리로 처리하기에는 너무 복잡함
    • 검색 조건은 쿼리로 처리하고, 필터링 조건은 애플리케이션 레벨에서 처리하기로 결정

    • ‘그 쿼리’가 보고싶다면 클릭하시오
        @Query("""
                SELECT C
                FROM Club AS C
                WHERE C.address.province = :province
                    AND C.createdAt <= :lastFoundCreatedAt
                    AND C.id < :lastFoundId
                    AND C.id IN (
                        SELECT CG.clubGenderId.club.id
                        FROM ClubGender CG
                        WHERE CG.clubGenderId.allowedGender IN :searchingGenders
                    )
                    AND C.id IN (
                        SELECT CS.clubSizeId.club.id
                        FROM ClubSize CS
                        WHERE CS.clubSizeId.allowedSize IN :searchingSizes
                    )
                    AND 0 < (
                        SELECT count(p.id)
                        FROM Pet p
                        WHERE p.member.id = :memberId 
                            AND p.gender IN (
                                SELECT CG2.clubGenderId.allowedGender
                                FROM ClubGender CG2
                                WHERE CG2.clubGenderId.club = c
                            ) 
                            AND p.sizeType IN (
                                SELECT CS3.clubSizeId.allowedSize
                                FROM ClubSize CS3
                                WHERE CS3.clubSizeId.club = c
                        )
                    )
                    AND C.status = 'OPEN'
                ORDER BY C.createdAt DESC, C.id DESC 
        """)
      

      그리고 이 쿼리를 본 도도의 반응…
      image

  1. Slice 인터페이스를 활용한 성능 최적화
    • Pageable 인터페이스 사용 시 전체 데이터 개수를 세기 위해 매 요청마다 전체 row에 대해 count 쿼리를 한 번 더 날림
    • Slice 인터페이스 사용 시 한번에 pageSize + 1 개의 데이터를 조회.
      만약 조회된 데이터 수가 pageSize + 1개인 경우, 다음 페이지가 있음을 의미함.
    • 무한 스크롤 방식에서는 페이지 번호와 같은 정보가 필요하지 않음. 다음 페이지를 위한 정보만 받아오면 되기 때문에 Slice 사용
  2. no-offset 방식 사용
    • offset 방식은 이미 읽었던 데이터 만큼 다시 읽어야하기 때문에, 뒤로 갈수록 점점 성능이 저하됨
    • no-offset 방식은 다음에 읽을 페이지 시작점을 조건문으로 빠르게 찾아 pageSize만큼 읽어오는 방식. offset 방식과 다르게, 페이지 번호가 늘어나더라도 매번 첫 페이지를 읽어온 것과 같은 성능을 냄
    • 클라이언트가 마지막으로 응답받은 club의 createdAt와 id 필드를 다음 페이지 요청에 포함하도록 구성함

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🖥 backend backend ✨ feat 기능 개발
Projects
Status: In Progress
Development

Successfully merging a pull request may close this issue.

2 participants