밤빵's 개발일지
[TIL]20240822 페이지네이션(Pagination) 본문
🤓페이지네이션(Pagination) 구현하기
페이지네이션(Pagination)은 웹 애플리케이션에서 많은 양의 데이터를 한 번에 모두 표시하지 않고, 페이지별로 나누어 사용자에게 데이터를 제공하는 방법이다. 이는 서버와 클라이언트의 성능을 최적화하는 데 필수적인 기술로,오늘 개발일지에서는 페이지네이션의 개념, 필요성, 구현 방법, 그리고 고려해야 할 사항들을 정리해봤다!
▶ 페이지네이션의 개념과 필요성
페이지네이션은 데이터의 양이 많아질수록 웹 페이지의 성능과 사용성에 직접적인 영향을 미치는 중요한 개념이다. 예를 들어, 수천 개의 데이터 를 한 번에 불러와 화면에 출력하게 되면, 사용자가 페이지를 로드하는 데 시간이 오래 걸리고, 브라우저가 멈추는 등의 문제가 발생할 수 있다. 페이지네이션을 적용하면 데이터는 여러 페이지로 나뉘어 표시되며, 사용자는 페이지를 넘기면서 더 많은 데이터를 확인할 수 있게 된다. 이러한 방식은 특히 게시판, 쇼핑몰 상품 리스트, 뉴스 피드 등과 같은 웹 애플리케이션에서 자주 사용된다.
▶페이지네이션이 필요한 이유?
→ 성능 최적화:
한 번에 모든 데이터를 가져오지 않기 때문에 서버와 클라이언트 모두의 성능이 향상된다.
→ 사용자 경험 개선:
페이지 로딩 시간이 줄어들고, 사용자는 데이터를 더 쉽게 탐색할 수 있다.
→ 데이터 전송량 감소:
필요한 데이터만 서버에서 클라이언트로 전송하기 때문에 네트워크 대역폭을 절약할 수 있다.
▶ 페이지네이션의 기본 개념
페이지네이션을 구현하기 위해서는 몇 가지 개념을 이해해야 한다.
→ 페이지 번호 (Page Number):
현재 사용자가 보고 있는 페이지의 번호로, 보통 1부터 시작하며, 사용자가 다음 페이지로 이동할 때마다 증가한다.
→ 페이지 크기 (Page Size):
한 페이지에 표시할 데이터의 수. 예를 들어, 한 페이지에 10개의 게시글을 보여주기로 설정하면, 페이지 크기는 10이 된다.
→ 전체 데이터 수 (Total Items):
전체 데이터 레코드의 수 데이터베이스에서 특정 조건에 따라 데이터를 조회할 때 이 값이 사용된다.
→ 전체 페이지 수 (Total Pages):
전체 데이터를 페이지 크기로 나눈 값. 이 값은 전체 데이터 수 / 페이지 크기로 계산된다.
▶ 페이지네이션 구현 방법
페이지네이션을 구현하는 방법은 백엔드와 프론트엔드에서 모두 다를 수 있다. 나는 백엔드를 공부하고있기때문에 백엔드에서 페이지네이션을 구현하는 방법을 정리했다. 가장 일반적으로 사용되는 방법은 SQL의 LIMIT과 OFFSET을 활용하는 것으로, 필요한 데이터만 선택적으로 가져올 수 있다.
▽ MySQL을 사용하여 데이터베이스에서 users 테이블의 데이터를 페이지네이션으로 가져온다고 가정했을 때,
SELECT * FROM users LIMIT 10 OFFSET 0; -- 1페이지 데이터를 가져옴 (페이지 크기: 10)
SELECT * FROM users LIMIT 10 OFFSET 10; -- 2페이지 데이터를 가져옴
SELECT * FROM users LIMIT 10 OFFSET 20; -- 3페이지 데이터를 가져옴
→ LIMIT은 한 번에 가져올 데이터의 수를 지정하고, OFFSET은 건너뛸 데이터의 수를 지정한다. 이를 통해 원하는 페이지의 데이터만 조회할 수 있게 된다.
▶ Spring Boot에서의 페이지네이션 구현
Spring Boot와 JPA(Hibernate)를 사용하여 페이지네이션을 구현하는 예시. Spring Data JPA는 기본적으로 페이지네이션을 지원하고, Pageable과 Page 인터페이스를 제공한다.
▽ User 엔티티와 UserRepository
package com.example.paginationdemo.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
package com.example.paginationdemo.repository;
import com.example.paginationdemo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface UserRepository extends JpaRepository<User, Long> {
Page<User> findAll(Pageable pageable);
}
package com.example.paginationdemo.service;
import com.example.paginationdemo.model.User;
import com.example.paginationdemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Page<User> getUsers(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return userRepository.findAll(pageable);
}
}
package com.example.paginationdemo.controller;
import com.example.paginationdemo.model.User;
import com.example.paginationdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public Page<User> getUsers(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.getUsers(page, size);
}
}
→ 예시 코드는 간단한 페이지네이션 API를 구현했다.. 클라이언트가 GET /users?page=1&size=10 요청을 보내면, 1페이지에 해당하는 10개의 사용자 데이터를 반환한다.
▶ 페이지네이션을 구현할 때 고려해야 할 사항
→ 성능 최적화:
데이터 양이 많아질수록 OFFSET의 성능이 떨어질 수 있다. 대규모 데이터를 다룰 때는 Keyset Pagination이나 Seek Pagination 등의 기술을 고려해야 한다.
▽ Keyset Pagination과 Seek Pagination
구분 | Keyset Pagination | Seek Pagination |
기본 원리 | 마지막으로 조회된 데이터의 키 값(ex: id)을 기준으로 다음 페이지를 가져온다. | 지정된 위치로부터 데이터를 찾고, 주어진 크기만큼 데이터를 가져온다. |
사용 사례 | 단일 컬럼(주로 id)을 기준으로 다음 데이터를 조회할 때 사용. | 복합 키나 여러 조건을 기준으로 페이지네이션을 수행할 때 사용. |
성능 | 대량의 데이터에서도 빠른 성능을 제공하며, 데이터의 크기에 비례해 성능 저하가 거의 없다. | Keyset Pagination과 유사하게 빠른 성능을 제공하지만, 더 복잡한 조건을 처리하는 데 적합하다. |
쿼리 예시 | SELECT * FROM users WHERE id > ? ORDER BY id ASC LIMIT 10; | SELECT * FROM users WHERE (id, name) > (?, ?) ORDER BY id, name ASC LIMIT 10; |
장점 | 단순하고 직관적이며, OFFSET을 사용하지 않아 데이터가 많을 때도 효율적이다. | 복합 조건에 대해 더 강력한 성능을 제공하고, 다양한 필터 조건과 함께 사용할 수 있다. |
단점 | 단일 조건 기준의 페이징만 가능하고, 복합 조건이 필요할 때는 복잡도가 증가할 수 있다. | 사용이 다소 복잡하고, 여러 조건을 기반으로 페이지네이션을 설계해야 하므로 쿼리가 복잡해질 수 있다. |
장점이 있는 경우 | 단순히 id와 같은 기본 키를 기준으로 데이터 목록을 페이지네이션할 때 적합하다. | 여러 조건을 기준으로 정렬하거나 필터링된 데이터를 페이지네이션할 때, 예를 들어 id와 name을 기준으로 할 때. |
→ 사용자 경험:
페이지네이션 UI를 설계할 때는 사용자가 쉽게 페이지를 이동하고 데이터를 탐색할 수 있도록 해야 한다. 페이지 번호, 다음/이전 버튼, 검색 기능 등을 고려할 수 있다.
→ 비동기 요청 처리:
프론트엔드에서는 AJAX를 사용하여 비동기적으로 페이지를 전환하면 더 나은 사용자 경험을 제공할 수 있다.
→ 캐싱:
동일한 데이터에 대한 반복된 요청을 줄이기 위해 캐싱을 적용할 수 있다. 이를 통해 서버 부하를 줄이고 응답 시간을 단축할 수 있다.
▶결론
페이지네이션은 웹 애플리케이션에서 성능을 최적화하고, 사용자 경험을 개선하기 위해 반드시 필요한 기능이다. Spring Boot와 JPA를 활용하면 쉽게 페이지네이션을 구현할 수 있고, 페이지네이션을 적용할 때는 성능 최적화와 사용자 경험을 함께 고려해야 한다. 페이지네이션을 제대로 이해하고 활용한다면, 대규모 데이터를 효율적으로 관리할 수 있을 것이다.
'개발Article' 카테고리의 다른 글
[TIL]20240824 MSA(Microservices Architecture) (0) | 2024.08.24 |
---|---|
[TIL]20240823 결제기능구현을 위한 시퀀스다이어그램 & 포트원 결제플로우 (0) | 2024.08.23 |
[TIL]20240821 Apache 와 Nginx (0) | 2024.08.21 |
[TIL]20240820 Authorization Grant (0) | 2024.08.20 |
[TIL]20240819 기본 포트는 왜 8080일까? (0) | 2024.08.19 |