PostgreSQL 벡터 검색, 어떻게 최적화할까? pgvector 성능 극대화 전략
들어가며
RAG(검색 증강 생성) 시스템을 구축하다 보면, 초기에는 잘 작동하던 벡터 검색이 데이터가 수만 건을 넘어서는 순간 급격히 느려지는 현상을 목격하게 됩니다. PostgreSQL의 pgvector는 매우 강력하지만, 인덱스 설정을 어떻게 하느냐에 따라 검색 속도가 수십 배 차이 날 수 있습니다.
오늘은 실무에서 벡터 검색의 성능을 극대화하기 위한 인덱스 선택 기준과 최적화 전략을 깊이 있게 살펴보겠습니다.
1. 인덱스 알고리즘의 선택: IVFFlat vs HNSW
pgvector에서 가장 중요한 결정은 어떤 인덱스 알고리즘을 사용할 것인가입니다.
IVFFlat (Inverted File with Flat Compression)
- 특징: 데이터를 클러스터링하여 리스트로 나눕니다. 검색 시 가장 가까운 리스트들만 확인합니다.
- 장점: 인덱스 빌드 속도가 빠르고 메모리 사용량이 적습니다.
- 단점: 데이터가 추가될 때마다 성능 유지를 위해 다시 빌드해야 하며, 검색 속도가 HNSW보다 느립니다.
HNSW (Hierarchical Navigable Small Worlds)
- 특징: 데이터 간의 계층적 그래프를 생성하여 탐색합니다.
- 장점: 높은 검색 정확도와 압도적인 속도를 제공합니다. 데이터 추가 후에도 인덱스를 재빌드할 필요가 없습니다.
- 단점: 인덱스 생성 시 메모리를 많이 사용하고 빌드 시간이 오래 걸립니다.
2. 실무 권장 인덱스 쿼리
대부분의 현대적인 프로덕션 환경에서는 HNSW를 권장합니다. Drizzle ORM을 쓰더라도 직접 SQL을 통해 인덱스를 생성해 주는 것이 좋습니다.
-- HNSW 인덱스 생성 예시
-- m: 노드당 최대 연결 수, ef_construction: 인덱스 빌드 시 탐색 범위
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
3. 성능을 높이는 3가지 핵심 튜닝
리콜(Recall)과 속도의 트레이드오프
HNSW 인덱스를 사용할 때 hnsw.ef_search 파라미터를 조정하면 검색 시 정확도(리콜)와 속도 사이의 균형을 맞출 수 있습니다.
-- 검색 세션에서 탐색 범위 확대 (정확도 향상, 속도 감소)
SET hnsw.ef_search = 100;
데이터 정규화(Normalization)
벡터 간의 코사인 유사도를 계산할 때, 벡터의 길이를 1로 정규화하여 저장하면 vector_ip_ops(내적) 연산자를 사용하여 훨씬 더 빠른 연산이 가능해집니다.
부분 인덱스(Partial Index) 활용
특정 카테고리나 사용자 그룹 내에서만 검색이 일어난다면, 전체 데이터가 아닌 특정 조건에 맞는 데이터에만 벡터 인덱스를 생성하세요.
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WHERE is_active = true AND category = 'tech';
4. 모니터링과 유지보수
인덱스가 실제로 잘 작동하고 있는지 확인하려면 EXPLAIN ANALYZE를 활용해야 합니다.
EXPLAIN ANALYZE SELECT * FROM documents
ORDER BY embedding <=> '[...query_vector...]' LIMIT 5;
이 결과에서 Index Scan이 아닌 Seq Scan이 나타난다면 인덱스가 제대로 타지 않고 있는 것이니 설정을 재검토해야 합니다.
마치며
PostgreSQL은 더 이상 단순한 관계형 DB가 아닙니다. pgvector와 적절한 인덱스 전략만 갖춘다면 수백만 건의 데이터에서도 밀리초(ms) 단위의 벡터 검색을 수행할 수 있는 훌륭한 AI 인프라가 됩니다.
여러분의 서비스 규모에 맞는 적절한 알고리즘을 선택하여 최고의 사용자 경험을 만들어 보세요. 궁금한 점이나 설정 시 겪은 어려움이 있다면 댓글로 공유해 주세요!