랭킹 API를 구현하면서 사용자를 모두 띄어주기에 페이징이 필요하다 판단했다.
기존 디자인에서 페이지 방식이 적용이 안되어 있기 때문에, 더보기 방식으로 구현하기로 했다.
이전 아띠즈 프로젝트에선 Group by를 사용하는 바람에 더보기 방식을 쓰되 No Offset으로 구현하진 못했다,,
이번 비치컴바인 프로젝트에선 더보기 방식을 쓰면서 No Offset을 적용해 성능 최적화를 해봤다!
No Offset이 왜 성능 최적화가 되는지, No Offset이 뭔지는 아래 블로그에 너무나 상세히 설명되어 있다.
사실 중간에 포기할 뻔 했다,,, No Offset 방식을 쓰려면 기준 key가 중복이 되면 안된다.
예시에선 id를 기준 key로 잡아서, No Offset 적용이 가능했는데,
예전 아띠즈 프로젝트에선 Group By 사용으로 인해 Key가 중복이 되어 정확한 결과를 반환할 수 없어서 No Offset을 사용할 수가 없었다.
비치컴바인 프로젝트에선 기준 key가 포인트와 id였다. 포인트는 중복이 되기에 처음에 No Offset 적용이 안되는가 했는데, 생각해보니 포인트와 id를 합한 것이 기준 key이기에 중복이 되지 않았다!
따라서 아래와 같이 Query를 짜줌으로써 No Offset을 적용할 수 있었다.
public List<MemberRankingResponse> findByTotalPointRanking(int pageSize, Long lastId, Integer lastPoint) {
return queryFactory
.select(Projections.fields(MemberRankingResponse.class,
member.id,
member.nickname,
member.image,
member.totalPoint.as("point")))
.from(member)
.where(
whereClause(lastId, lastPoint)
)
.orderBy(member.totalPoint.desc(), member.id.asc())
.limit(pageSize)
.fetch();
}
private BooleanExpression whereClause(Long lastId, Integer lastPoint) {
if(lastId != null && lastPoint != null) {
return member.totalPoint.loe(lastPoint).and(member.id.gt(lastId));
}
return null;
}
Java
복사
클라는 아래와 같은 규칙으로 요청한다.
예시) 데이터를 2개씩 넘겨온다 가정한다면,
첫번째 페이지일 때
요청) localhost:8080/members/ranking?range=all&pageSize=2
응답) 첫 번째 페이지
Mike id_5 5000point
Dan id_3 3000point
두 번째 페이지 이상일 때부턴 바로 전 페이지의 마지막 데이터의 id와 point를 같이 넘겨줍니다.
요청) localhost:8080/members/ranking?range=all&pageSize=2&lastId=3&lastPoint=3000
응답) 두 번째 페이지
Choo id_4 3000point
Rami id_6 2000point
요청) localhost:8080/members/ranking?range=all&pageSize=2&lastId=6&lastPoint=2000
응답) 세 번째 페이지
Lee id_1 1000point