2025-12-04
오늘 배운 것
- 검색 기능 구현시 극한의 성능 어캐 낼껀지
- 검색 기능 성능 최적화 전체 구조
- SQL 최적화
- 인덱스 설계
- 캐싱 전략
- 전문 검색 엔진 도입(Elasticsearch)
- 아키텍처/데이터 모델 최적화
- SQL 자체 성능 최적화
- 가장 중요한 5가지
- WHERE 조건에 인덱스 컬럼 사용
- LIKE %keyword% → 인덱스 절대 못탐
- LIKE ‘keyword%’ → 인덱스 사용가능
- LIKE ‘%keyword%’ 는 전문 검색 엔진 필요
- 정렬 → 인덱스 없으면 전체 정렬
- LIMIT + OFFSET 시 뒤로 갈수록 느려짐
- 불필요한 JOIN 제거
- 가장 중요한 5가지
- 인덱스 설계
- B+Tree 인덱스
- 가장 기본적이고 가장 많이 사용되는 인덱스
- 속도
- 동등 비교(=) → 매우 빠름
- 범위 검색 (≥, ≤, BETWEEN) → 빠름
- 복합 인덱스
- 예 : (category_id, created_at)
- 정렬 + 필터링을 동시에 빠르게 만들 수 있음
- categori_id로 필터링
- created_at 으로 정렬
- 정렬 + LIMIT 조회는 인덱스로 하면 거의 메모리급 속도
- 커버링 인덱스
- SELECT하는 모든 컬럼이 인덱스에 있으면 테이블로 안 내려가고 인덱스만 읽음
- B+Tree 인덱스
- 캐싱
- 검색 기능은 보통 동일한 키워드로 반복 검색되는 경우가 많음
- Redis 캐싱
- 검색 결과를 Redis 에 저장 → 즉시 응답
- TTL(만료시간) 설정해서 최신성 유지
- Local Cache (Caffeine)
- API 서버 메모리에 저장
- 네트워크 타지 않아 속도 더 빠름
- 단, 서버가 여러대면 일관성 깨짐
- 쿼리 캐시 전략
- 핫한 키워드 캐시
- Top N 조회수 높은 문서 캐시
- 최근 검색 기록 캐시
- 실제 서비스에서는 검색은 70% 캐시, 30% 실쿼리
- 전문 검색 엔진
- SQL LIKE로는 ‘%word%’ 전체 문자열 검색을 절대 빠르게 할 수 없음
- 대규모 서비스는 반드시 Elasticsearch 같은 검색 엔진을 사용
- 빠른 이유
- 역 인덱스
- 문서 → 단어, 가 아닌 단어 → 해당 문서 리스트 구조로 저장
-
검색할 때 테이블 전체 스캔이 아니라 단어 사전에서 바로 문서를 찾음
“안녕 나는 수아야” → 안녕: [문서1] → 나는: [문서1] → 수아야: [문서1]
- 형태소 분석기
- 한국어는 띄어쓰기만으로는 검색 성능이 안 나오기 때문에 형태소 분석으로 단어를 쪼갬
-
검색 정확도와 속도 엄청 증가
“네이버에서 실시간 검색” → 네이버 / 실시간 / 검색
- 스코어링
- ES는 단순 필터링이 아니라 연관도 점수를 계산해서 정렬까지 해줌
- 역 인덱스
- 데이터 모델링 / 구조 최적화
- 테이블 분리(샤딩 / 파티셔닝)
- 검색 대상이 많으면
- 날짜 기반 파티셔닝
- 카테고리 기반 분리
- Elasticsearch에 색인 분산
- 비정규화
- 조인 비용을 줄이기 위해 읽기 전용 필드를 중복 저장
- 예
- 게시글 검색에 user.name 조인이 느리면 게시글 테이블에 user_name을 아예 둠
- 검색 대상이 많으면
- 테이블 분리(샤딩 / 파티셔닝)
- 실제 서비스에서 공통으로 사용
- AND/OR 조합 최소화
- 복잡한 조합은 필터 스플릿/리팩터링
-
예
WHERE (category = 1 AND tags LIKE '%A%') OR (category = 1 AND tags LIKE '%B%')- 이런 쿼리는 인덱스를 못탐
-
조건을 쪼개서
WHERE category = 1 AND (tags LIKE '%A%' OR tags LIKE '%B%') //혹은 WHERE category = 1 ///으로 먼저 필터링 하여 검색 범위를 대폭 줄임 //또는 태그를 역 정규화 해서 검색 엔진에 넣음 -> 쿼리가 단순
- LIMIT + OFFSET 위주라면 Cursor 기반 페이징
- OFFSET이 커질수록 느려짐
- Cursor 방식으로 즉시 점프 가능
- 몇개 버리고 조회가 아니라 뭐 특정 필드의 값 이후 전체를 조회해서 무한 스크롤 상화에서도 빠르게 조회가능
- 쿼리로 구현하는 것
- 캐시 앞단에 CDN 사용(정적 검색 결과)
- 자동완성, 추천 검색어 같은 건 CDN 에도 가능
- 실시간 인덱싱 vs 배치 인덱싱 전략 분리
- 실시간으로 인덱스 업데이트하기엔 너무 비싸므로 변경사항만 파이프라인으로 색인
- AND/OR 조합 최소화
- 검색 기능 성능 최적화 전체 구조