Slice
public interface Slice<T> extends Streamable<T> {
int getNumber();
int getSize();
int getNumberOfElements();
List<T> getContent();
boolean hasContent();
// ...
}
JPA에서 정의한 Slice 인터페이스는 다음과 같다. 현재 페이지의 데이터들을 불러오고, 다음 페이지가 있는지 여부를 확인한다.
Page
public interface Page<T> extends Slice<T> {
long getTotalElements();
int getTotalPages();
//...
}
Page 인터페이스는, Slice를 상속받기때문에, Slice에서 쓸수있는 모든 기능을 쓸수있으며, 총 페이지 수 , 총 element수를 받아올 수 있는 추가적인 기능을 제공한다.
실제 수행되는 쿼리
Page의 경우, Limit을 활용해 조회를 한 후 , 전체 element개수를 조회하기위해 추가 쿼리 1회가 실행된다 . (Select Count(*) from ~)
Slice의 경우에는, Limit 의 값을 기존 페이지 사이즈 + 1을 함으로써 다음 페이지가 있는지 확인하므로, 1번의 쿼리로 조회가 가능하다.
따라서 데이터의 총 수가 많으면, SELECT COUNT(*) 가체가 부담이 되기때문에, 데이터의 수가 많을 경우 Page의 성능이 급감한다.
그럼에도 Page를 사용하는 이유는 검색 페이지와 같은 페이지 수가 중요한 기능이나, 사용자의 편의를 위한 경우 사용하고,
Slice를 사용하는 경우는, 전체 페이지 수, 전체 element수가 필요없는 모바일 환경의 무한스크롤 같은 환경에서 사용한다.
결론
웹 프로젝트를 하다가 JPQL로 Join문을 쓰며 최대한 쿼리를 하나로 최적화하는 과정을 했었는데,
아무리 쿼리문을 하나로 줄여도 추가로 발생 하는 쿼리가 생겨서 이상함을 느껴서 찾아보니
Page의 특성 떄문에 그렇다는 것을 알게되었다. 제대로 알지 못하고 그냥 사용만 하는것이 아니라,
뭐든 제대로 알고 써야한다는 것을 깨닫게 되었고,
나중에 Page를 쓰지 않아도 되는 상황에서 바보처럼 Page를 사용하지말고,
최대한 서버의 성능 부담을 덜어 줄 수 있는 Slice도 고려해야 한다.
'Backend > Spring Boot' 카테고리의 다른 글
[Spring boot] Spring AOP - CGLIB Proxy vs Dynamic Proxy (0) | 2024.12.31 |
---|---|
[SpringBoot] QueryDsl의 Pagenation + PageableExecutionUtils을 이용해 count 쿼리 최적화 (1) | 2024.11.19 |
[Spring Boot] Pageable을 이용해 페이지네이션구현(+JPA) (0) | 2024.09.23 |
[Spring Boot] Spring AI + Google vertex ai gemini 이미지 처리하기 (0) | 2024.06.27 |