๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

[JPA] ์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ Pagenation ๊ตฌํ˜„ํ•˜๊ธฐ

by young-ji 2023. 3. 1.

Spring Data JPA์—์„œ๋Š” Pagination์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก Pageable ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์˜คํ”„์…‹ ๊ธฐ๋ฐ˜ Pagenation

DB์˜ offset์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ‘ํŽ˜์ด์ง€’ ๋‹จ์œ„๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์š”์ฒญ/์‘๋‹ต ํ•œ๋‹ค.

 

 

controller

/**
 * ๊ฒŒ์‹œ๋ฌผ page ์กฐํšŒ
 *
 * @param pageable
 * @return Page<PostDto>
 */
@GetMapping(produces = APPLICATION_JSON_VALUE)
public ApiResponse<Page<PostDTO.Response>> getPosts(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
    Page<PostDTO.Response> pages = postService.findAll(pageable);
    return ApiResponse.ok(pages);
}

service

public Page<PostDTO.Response> findAll(Pageable pageable) {
    return postRepository.findAll(pageable)
            .map(postConverter::convertResponseOnlyPostDto);
}

repository Page<T> findAll(Pageable pageable) ๋ฉ”์†Œ๋Š” SpringDataJPA์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•ด ์ฃผ๋Š” CRUD์ด๋‹ค.

 

 

 

ํ€ด๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‚˜๊ฐ€๋Š” ์ง€ ํ™•์ธํ•ด๋ณด์ž

@Test
@DisplayName("pageNation ์ฟผ๋ฆฌ ํ™•์ธ")
public void findAll(){
    Page<Post> pages = postRepository.findAll(PageRequest.of(0,10)); // page : 0 , size : 10
}

 

MySQL ์—์„œ๋ผ๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ OFFSET ์ฟผ๋ฆฌ์™€ LIMIT ์ฟผ๋ฆฌ์— ์ฝค๋งˆ๋ฅผ ๋ถ™์—ฌ '๊ฑด๋„ˆ ๋›ธ' row ์ˆซ์ž๋ฅผ ์ง€์ •ํ•˜์—ฌ ํŽ˜์ด์ง€๋„ค์ด์…˜์„ ๊ตฌํ˜„ํ•œ๋‹ค.

SELECT id FROM products ORDER BY id LIMIT (one_size *(page-1)), one_size;

-

SELECT * FROM products LIMIT ์ˆซ์ž OFFSET ํŽ˜์ด์ง€ ๋„˜๋ฒ„;

OFFSET ํ‚ค์›Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ์‹. ๊ฒฐ๊ณผ์™€ ์„ฑ๋Šฅ์€ ๋™์ผํ•˜๋‹ค.

 

 

Pageable์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•ด ๋ณด๋ ค๊ณ ๋„ ํ•˜์˜€์œผ๋‚˜ JPQL๋Š”  limit ํ‚ค์›Œ๋“œ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค. JPA์—์„œ limit์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋ฌด์กฐ๊ฑด pagenation๋ฅผ ํ•˜๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ์ฟผ๋ฆฌ๋กœ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด NativeQuery๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ QueryDSL์„ ์‚ฌ์šฉํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

PageRequest

PageRequest์— ์˜ํ•ด Pageable์— ํŽ˜์ด์ง• ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ ๊ฐ์ฒดํ™” ๋œ๋‹ค.

  • of(int page, int size) : 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ๊ฐœ์ˆ˜. ์ •๋ ฌ์ด ์ง€์ •๋˜์ง€ ์•Š์Œ
  • of(int page, int size, Sort sort) : ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ๊ฐœ์ˆ˜, ์ •๋ ฌ ๊ด€๋ จ ์ •๋ณด
  • of(int page int size, Sort sort, Direction direction, String ... props) : 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ๊ฐœ์ˆ˜, ์ •๋ ฌ์˜ ๋ฐฉํ–ฅ๊ณผ ์ •๋ ฌ ๊ธฐ์ค€ ํ•„๋“œ๋“ค

 

@PageableDefault

spring mvc์— ์˜ํ•ด ์ปจํŠธ๋กค๋Ÿฌ์—์„œ Pageable์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ๋Š” pageable์— PageRequest ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•ด์ค€๋‹ค.

→ ์ด๋•Œ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด page(0๋ถ€ํ„ฐ ์‹œ์ž‘),size,sort๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

์Šคํ”„๋ง ๋ถ€ํŠธ์—์„  ๊ธฐ๋ณธ์œผ๋กœ defualt size 20, max page size 2000์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค.

@PageableDefault ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ณ„ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ธฐ๋ณธ defult ๊ฐ’์ด ์žˆ๋”๋ผ๋„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

 

 

offset ์ฟผ๋ฆฌ์˜ ํผํฌ๋จผ์Šค ์ด์Šˆ

๊ทน๋‹จ์ ์œผ๋กœ 10์–ต๋ฒˆ์งธ ํŽ˜์ด์ง€์— ์žˆ๋Š” ๊ฐ’์„ ์ฐพ๊ณ ์‹ถ๋‹ค๋ฉด offset์— ๋งค์šฐ ํฐ ์ˆซ์ž๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค. ์ •๋ ฌ ๊ธฐ์ค€ ํ•ด๋‹น row๊ฐ€ ๋ช‡๋ฒˆ์งธ ์ˆœ์„œ์ธ์ง€ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ ์ง€์ •๋œ offset๊นŒ์ง€ ๋ชจ๋‘ ๋งŒ๋“ค์–ด ๋†“์€ ํ›„ ์ง€์ •๋œ ๊ฐฏ์ˆ˜๋ฅผ ์ˆœํšŒํ•˜์—ฌ ์ž๋ผ๋Š” ๋ฐฉ์‹์ด๋‹ค. ๋•Œ๋ฌธ์— ํผํฌ๋จผ์ˆ˜๊ฐ€ ์ด์— ๋น„๋ก€ํ•˜์—ฌ ๋–จ์–ด์ง€๊ฒŒ ๋œ๋‹ค.

Faster Pagination in Mysql – Why Order By With Limit and Offset is Slow?

 

Why Order By With Limit and Offset is Slow - Faster Pagination in Mysql

Paging using LIMIT and OFFSET clauses in MySQL can be very slow. In this article we describe the seek method that allows a faster, more stable paging performance.

www.eversql.com

 

 

 

 

 

์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€์„ ํ†ตํ•ด ์•Œ๋ ค์ฃผ์„ธ์š”. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. 

๋Œ“๊ธ€