네로개발일기

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

3-2. 첫 페이지 조회 결과 캐시하기

처음 검색 시 조회된 count 결과를 응답 결과로 내려주어 JS에서 이를 캐싱하고 매 페이징 버튼마다 count 결과를 함께 내려주는 것이다.

Repository에서는 요청에 넘어온 항목 중 캐싱된 count 값이 있으면 이를 재사용하고, 없으면 count 쿼리를 수행한다.

 

- 첫 1페이지 요청 시 count 쿼리를 날려서 totalCount를 가져온다. 

- 2페이지 이상 요청 시 JS에서 캐싱한 totalCount를 같이 보내서 count 쿼리를 날리지 않고 기존의 totalCount를 같이 보내서 count 쿼리를 날리지 않는다.

 

이 방식은 다음과 같은 상황에서 도움이 된다.

- 조회 요청이 검색 버튼과 페이지 버튼 모두에서 골고루 발생하고

- 실시간으로 데이터가 적재되지 않고, 마감된 데이터를 사용할 경우

 

물론 JS에서 캐싱하고 있기 때문에 브라우저를 새로고침하게 되면 count는 다시 초기화가 되어 첫 조회시 다시 쿼리가 수행되게 된다.

 

3-2-1. 구현 코드

기존 페이징 쿼리는 동일하다.

public Page<BookPaginationDto> paginationCount(Pageable pageable, String name) {
    JPQLQuery<BookPaginationDto> query = querydsl().applyPagination(pageable,
            queryFactory
                    .select(Projections.fields(BookPaginationDto.class,
                            book.id.as("bookId"),
                            book.name,
                            book.bookNo,
                            book.bookType
                    ))
                    .from(book)
                    .where(
                            book.name.like(name + "%")
                    )
                    .orderBy(book.id.desc()));

    List<BookPaginationDto> items = query.fetch(); // 데이터 조회
    long totalCount = query.fetchCount(); // 전체 count
    return new PageImpl<>(items, pageable, totalCount);
}

private Querydsl querydsl() {
    return Objects.requireNonNull(getQuerydsl());
}

검색 / 페이징 버튼 클릭시 cache 된 count를 사용하도록 개선하기 위해서는 다음의 코드가 추가되어야 한다.

- 프론트 영역에서 넘겨준 count 값이 요청 필드에 포함시킨다.

- Repository에서는 해당 count 값이 있을 경우엔 그대로 페이징 결과에 포함시키고, 없으면 실제 count 쿼리를 실행한다.

 

public Page<BookPaginationDto> paginationCountCache(Long cachedCount, Pageable pageable, String name) {
    
    // cacheCount는 프론트 영역에서 넘겨준 count 값이다.
    JPQLQuery<BookPaginationDto> query = querydsl().applyPagination(pageable,
            queryFactory
                    .select(Projections.fields(BookPaginationDto.class,
                            book.id.as("bookId"),
                            book.name,
                            book.bookNo,
                            book.bookType
                    ))
                    .from(book)
                    .where(
                            book.name.like(name + "%")
                    )
                    .orderBy(book.id.desc()));

    List<BookPaginationDto> elements = query.fetch(); // 데이터 조회
    long totalCount = cachedCount != null ? cachedCount : query.fetchCount(); // 전체 count: cacheCount가 없으면 실제 count 쿼리를 수행시킨다.
    return new PageImpl<>(elements, pageable, totalCount);
}

private Querydsl querydsl() {
    return Objects.requireNonNull(getQuerydsl());
}

3-2-2. 결론

한번 조회된 동일 조건의 count에서는 클라이언트 영역에서 저장 후 요청시마다 재사용하는 방식을 사용하면 추가 쿼리 요청이 최소화된다.

단점은

- 첫번째 페이지 조회가 대부분일 경우 효과가 없다.

- 실시간으로 데이터 수정이 필요해서 페이지 버튼 반영이 필요한 경우 사용할 수 없다.

결국 새로고침(또는 버튼 클릭을 통한 페이지 이동)을 하기 전까지 실시간성이 떨어진다.

 

 

 출처 

https://jojoldu.tistory.com/531

 

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !