컴공생의 발자취

[TIL] 검색+필터 기능 설계 시 고려할 점 (feat. DB, API) 본문

🌃 TIL

[TIL] 검색+필터 기능 설계 시 고려할 점 (feat. DB, API)

MNY 2025. 1. 21. 14:45
728x90
반응형
목차
1. 검색과 필터
2. DB
3. API 설계
4. 성능 최적화
들어가며
  • 고민하게 된 배경

사이드 프로젝트를 시작하면서 검색 기능을 맡았다.

설계 시에 어떤 걸 고려해야 되는지 알아보며 그 과정을 기록한 글이다.

  • 간단한 내용 요약

해당 글은 검색과 필터의 차이를 비교하며 시작한다. DB에서는 어떤 테이블과 속성이 사용되는지 정의한다. 또한, 인덱스의 사용 예를 간략하게 명시한다. 그후 api를 설계하며 살펴봐야 할 4가지 포인트를 짚어준다. 정렬, 페이징, 동적 쿼리 비교분석과 RESTful API의 쿼리파라미터이다. 마지막으로 성능 최적화를 할 수 있는 방법이 무엇이 있는지 기술한다.

 

 1. 검색과 필터 

검색과 필터가 함께 사용되는 경우가 대다수다. 검색 기능에 대해 고민하다 검색과 필터가 어떻게 다른지에 대해 생각했다.

검색 기능과 필터 기능은 서로 다른 개념이지만, 보완적으로 사용된다.

표를 이용해 구분해본다면 다음과 같다.

구분 검색 필터
입력 방식 사용자가 키워드 입력 선택한 조건에 따라 데이터 제한
사용 목적 특정 데이터를 찾기 위해 데이터를 분류하거나 좁히기 위해
결과 범위 키워드와 관련된 데이터 전반 설정한 조건을 충족하는 데이터만 표시
응용 예시 블로그에서 “QueryDSL” 키워드 검색 2023년도 설정 시 조건에 맞는 글만 표시

 

 2. DB 

ERD는 데이터베이스 설계를 위한 중요한 단계이다. 검색과 필터는 자주 조합되어 사용되므로, 통합적으로 설계한다.

먼저, 검색하려는 테이블과 속성부터 정의한다.

  • 테이블 : POST, PR
  • 속성 : title(제목), description(내용)

텍스트 검색이 많은 경우, 인덱싱을 설정할 수도 있다. (예 : MySQL의 FULLTEXT, PostgreSQL의 GIN 인덱스)

다음으로 필터링하려는 테이블과 속성도 정의한다.

  • 테이블 : BASIC_TECH_STACK, POST, PR
  • 속성 : tech_name(기술스택), position(역할), recruitment(모집상태), progress(진행방식)

 

 3. API 설계 

  • 정렬

기본 정렬을 어떻게 할 것인지부터 결정해야 한다. 기본적으로 기본 정렬은 최신순으로 정렬된다. 하지만, 기본 정렬을 모집이 마감된 것을 제외하고 최신순으로 보여줄 수도 있으므로 이러한 부분도 고려한다.

  • 페이징 처리

검색과 필터 결과가 많아질 수 있으므로 기본적으로 페이징 처리를 해주어야 한다. 또한, 한 페이지에 표시할 항목의 수도 함께 고려해야 한다. limit, offset을 사용한다. API 응답에 totalCount, CurrentPage, totalPages 등을 포함하다.

  • 동적 쿼리 생성 : queryDSL, Criteria api, SQL Builder, sql raw

사용자가 필터링 조건을 조합할 수 있으므로, 동적 쿼리 생성이 필요하다.

동적 쿼리 생성은 다양한 방법을 적용할 수 있다. QueryDSL, Criteria API, SQL Builder, Raw SQL이 있다. 각각 특징 비교와 추천 사용 시점에 대해 알아보았다.

 

비교표

특징 QueryDSL Criteria API SQL Builder Raw SQL
타입 안전성 ✅ 컴파일 타임 오류 방지 ✅ 컴파일 타임 오류 방지 ✅ 일부 도구에서 지원 ❌ 런타임 오류 발생 가능
가독성 ✅ SQL-like 코드로 직관적 ❌ 장황하고 복잡 ✅ 메서드 체인으로 구조적 ❌ 문자열로 읽기 어려움
유지보수성 ✅ 리팩토링 용이 ❌ 복잡한 쿼리는 관리 어려움 ✅ 유지보수 비교적 쉬움 ❌ 쿼리 변경 시 오류 발생 가능
SQL 제어 ✅ 제한적 SQL 제어 가능 ❌ JPA에 의존적 ✅ 세부 제어 가능 ✅ 완전한 제어 가능
러닝 커브 ❌ Q 클래스 생성 학습 필요 ✅ 표준 API라 학습 쉬움 ❌ 도구 사용법 학습 필요 ✅ 별도 학습 필요 없음
JPA 통합성 ✅ 자연스럽게 연동 ✅ 표준 API로 자연스럽게 연동 ❌ 별도 매핑 필요 ❌ 별도로 연동 필요
사용 사례 중~복잡한 쿼리 작성 간단한 동적 쿼리 작성 고성능 쿼리, SQL 제어 필요 시 간단한 쿼리 or 최적화된 SQL

 

추천 사용 시점

  1. QueryDSL : 유지보수성과 가독성이 중요한 JPA 기반 프로젝트
  2. Criteria API : JPA 표준 API를 사용하는 간단한 동적 쿼리
  3. SQL Builder : DBMS 제어가 필요한 고성능, 복잡한 SQL 작성
  4. Raw SQL : 특정 DBMS에 최적화된 쿼리나 간단한 SQL 작업

결론은 QueryDSL 사용하기로 했다. 이유는 현재 확장 가능성이 있기 때문에 유지보수와 가독성이 뛰어나야 하기 때문이다.

 

  • restful api

이제까지 했던 것을 기반으로 API를 설계해야 한다. 하나의 엔드포인트로 검색과 필터를 함께 처리해야한다. 조회이기 때문에 http method는 GET을 사용한다. 참고로 RESTful API 설계를 위해서는 몇 가지 지켜야 할 것들이 있다. 간단하게 검색 해보는 것을 추천한다.

 

API 설계 구조

  • Base URL : /post
  • HTTP Method : GET
  • 기능 : 검색, 필터, 페이징 처리

ex. GET /projects?search=검색어&tech_name=Java,Spring&position=Backend&recruitment=open&progress=remote&page=1&size=10

 

쿼리 파라미터 설명

파라미터 설명 예시
search 검색어(title, description에서 검색) search=Spring Boot
tech_name 기술 스택 필터 (여러 개 선택 가능, 쉼표로 구분) tech_name=Java,Spring
position 역할 필터 position=Backend
recruitment 모집 상태 필터 (e.g., open, closed) recruitment=open
progress 진행 방식 필터 (e.g., remote, online, offline) progress=remote
page 페이징 처리: 조회할 페이지 번호 page=1
size 페이징 처리: 한 페이지에 표시할 항목 수 size=10

 

응답 예시

{
  "totalCount": 50,
  "currentPage": 1,
  "totalPages": 5,
  "pageSize": 10,
  "data": [
    {
      "content" : "내용"
    }, ...  
  ]
}

 

 4. 성능 최적화 

추가적으로 성능을 최적화하는 방법에 대해 함께 조사를 해보았다.

검색, 필터링, 인덱스, 캐싱, 비동기 처리, 데이터 분산 처리 이렇게 6가지 정도 나왔다.

  • 검색
    • Elasticsearch
    • Partial Matching (N-gram, Prefix Matching) : 자동완성 등에서 자주 사용
  • 필터링
    • 복합 인덱스 : 자주 사용되는 필터 조건을 조합한 인덱스 생성
    • Materialized View : 미리 계산된 데이터를 별도 테이블로 저장
  • 인덱스 : 자주 사용하는 검색 필드와 필터 조건에 인덱스 설정
  • 캐싱 : Redis, Memcached를 사용해 반복 요청 처리. 동일한 필터 결과 캐싱.
  • 비동기 처리 : 검색과 필터링 요청이 복잡한 경우, 비동기적으로 처리해 사용자에게 빠르게 응답
  • 데이터 분산 처리
    • 데이터베이스 샤딩 : 데이터를 여러 개의 작은 데이터베이스(Shard)로 나누는 기술
    • 읽기 전용 복제본 (Read Replica)

 

 

 

 

728x90
반응형