LLM WikiAccess-protected knowledge portal

WIKI

벡터 검색 성능 튜닝: ef_search, recall 측정, 벤치마킹

"빠르고 정확하게"는 공짜가 아니다 벡터 데이터베이스는 근사 최근접 이웃 ANN, Approximate Nearest Neighbor 을 반환한다. 정확도 Recall 와 처리량 QPS ·지연 Latency 은 반비례한다. 인덱스 탐색 범위를 넓히면 더 많은 진짜 이웃을 찾지만 그만큼 더 많은 후보를 계산한다. 이 챕터는 이 트레이드오프를 측정하고, 인덱스별 핵심 파라미터를 조정하며, 프로덕션에서 실제로 벤치마킹하는 방법을 다

경로human/study/content/vector-databases/05-vector-search-performance-tuning-recall-benchmark.md
카테고리Study
태그#benchmark #mysql #performance #recall #search #study #tuning

"빠르고 정확하게"는 공짜가 아니다

벡터 데이터베이스는 근사 최근접 이웃(ANN, Approximate Nearest Neighbor)을 반환한다. 정확도(Recall)와 처리량(QPS)·지연(Latency)은 반비례한다. 인덱스 탐색 범위를 넓히면 더 많은 진짜 이웃을 찾지만 그만큼 더 많은 후보를 계산한다.

이 챕터는 이 트레이드오프를 측정하고, 인덱스별 핵심 파라미터를 조정하며, 프로덕션에서 실제로 벤치마킹하는 방법을 다룬다.


Recall@K: 정확도 측정의 기본 단위

Recall@K는 가장 널리 쓰이는 ANN 정확도 지표다.

Recall@K = |반환된 K개 ∩ 진짜 Top-K| / K

예: K=10으로 검색했을 때 반환된 10개 중 실제 Top-10에 속하는 것이 9개면 Recall@10 = 0.90.

진짜 Top-K는 전체 벡터에 대해 brute-force(FLAT 인덱스)로 계산한 결과다. 따라서 Recall 측정에는 별도의 정답 셋(ground-truth)이 필요하다.

Recall@K 측정 흐름 쿼리 벡터 N개 샘플 FLAT (Brute-Force) 전체 벡터와 거리 계산 정답 Top-K 생성 ANN 인덱스 HNSW/IVF 근사 검색 파라미터별 결과 생성 교집합 계산 |ANN 결과 ∩ 정답| / K 쿼리별 Recall 평균 Recall@K 값 0.0 ~ 1.0 (1.0 = 완벽) 파라미터별 결과 비교 실무 Recall 목표 기준 0.95+ : 시맨틱 검색·RAG 파이프라인 일반 기준. 이 이하면 검색 품질이 눈에 띄게 저하됨. 0.99+ : 중복 검출·의미 유사 쌍 탐색처럼 높은 정확도가 필요한 작업. 지연이 크게 증가함 (0.95→0.99 구간에서 급격히 가팔라짐). 0.90 이하 : 추천 시스템처럼 top-K 순서보다 다양성이 중요한 경우. 저지연·고QPS 우선 상황.
Recall@K 개념과 측정 흐름

HNSW 파라미터 튜닝

HNSW는 빌드 시 파라미터와 쿼리 시 파라미터가 분리된다.

빌드 파라미터 (인덱스 생성 시 결정)

파라미터역할기본값조정 지침
M노드당 최대 엣지 수16높을수록 recall↑, 메모리↑. 범용: 16. 고recall: 32~64
ef_construction / efConstruction빌드 시 후보 풀 크기100~200최소 M × 2. 고품질 빌드: 400~800

Mef_construction인덱스 재빌드 없이 변경 불가다. 빌드 시 충분히 높게 설정하는 것이 중요하다.

쿼리 파라미터 (쿼리마다 조정 가능)

파라미터 이름엔진별 표기역할
ef (search)pgvector: hnsw.ef_search, Qdrant: hnsw_ef, Milvus: ef쿼리 시 탐색 후보 풀 크기
ef_search 효과:
- ef = 32  → 빠름, recall 약 0.85~0.90
- ef = 64  → 균형, recall 약 0.92~0.95
- ef = 128 → 느림, recall 약 0.97~0.99
- ef = 512 → 매우 느림, recall 0.995+

실용 규칙: ef_search = 2 × K부터 시작해 recall을 측정하며 목표치까지 올린다.

ef_search와 지연·QPS 관계

ef_search 증가에 따른 Recall · 지연 변화 지연 (ms) 낮음 높음 ef_search 값 → 32 64 128 256 512 지연 Recall Recall ~0.87 Recall ~0.97 Recall ~0.995 ⚠ 0.95→0.99 구간 지연이 급격히 상승 (3~5×) Recall 곡선은 포화(수확 체감), 지연 곡선은 선형 증가에 가까움 → 목표 Recall에서 ef 고정 후 QPS 측정이 실용적
HNSW ef_search 튜닝: Recall-Latency 곡선

IVF 계열 파라미터 튜닝

IVF(Inverted File Index)는 k-means로 벡터 공간을 nlist개 클러스터로 분할하고, 쿼리 시 nprobe개 클러스터만 탐색한다.

빌드 파라미터

파라미터역할권장 설정
nlist클러스터 수sqrt(N) 이상. 100만 벡터 → 1024~4096

쿼리 파라미터

파라미터역할범위
nprobe탐색할 클러스터 수1 ~ nlist. nprobe/nlist = 탐색 비율
nprobe 튜닝:
- nprobe = 1    → 최고속, recall 낮음 (~0.6~0.7)
- nprobe = 16   → 균형 (~0.90)
- nprobe = 64   → 고정확 (~0.97)
- nprobe = nlist → FLAT과 동일 (완전 탐색)

IVF는 필터링과 궁합이 나쁘다: 필터 조건이 강할수록 각 클러스터 내 후보가 줄어들어 nprobe를 크게 올려야 recall을 유지할 수 있다. 이 경우 HNSW가 더 나은 선택이다.


인덱스별 튜닝 요약표

인덱스빌드 파라미터쿼리 파라미터메모리필터 대응
FLAT없음없음벡터 크기 그대로완벽
IVF_FLATnlistnprobe벡터 + 클러스터 중심보통
IVF_SQ8nlistnprobe1/4보통
IVF_PQnlist, m, nbitsnprobe1/m~보통
HNSWM, ef_constructionef벡터 + 그래프좋음
DiskANNsearch_listsearch_list10% (나머지 SSD)보통

벤치마킹 도구

ANN-Benchmarks

표준 오픈소스 벤치마크. 고정 데이터셋(SIFT-1M, GIST-1M, GloVe 등)으로 Recall vs QPS Pareto 곡선을 생성한다.

# ANN-Benchmarks 실행 예시
python run.py --dataset sift-128-euclidean \
              --algorithm hnswlib \
              --runs 3
python plot.py --dataset sift-128-euclidean

Pareto 곡선: 같은 QPS에서 recall이 가장 높거나, 같은 recall에서 QPS가 가장 높은 설정만 표시. 우측 하단에 가까울수록 우수한 알고리즘·설정이다.

한계: 단일 스레드·소규모 데이터셋 중심이라 멀티스레드 프로덕션 환경을 그대로 반영하지 않는다.

VDBBench (구 VectorDBBench)

Zilliz가 공개한 실사용 환경 벤치마크. 지속 부하(sustained concurrency), P99 지연, Recall을 동시에 측정한다.

VDBBench 측정 흐름:
1. Serial test (1,000 쿼리, 단일 스레드)
   → recall, P99 latency 이론적 상한 파악
2. Concurrency test (점진적 동시 접속 증가)
   → 최대 지속 QPS (max_qps) 탐색
3. 각 설정에서 recall 함께 기록
   → recall과 QPS를 함께 비교

핵심: 성능 숫자는 recall과 항상 같이 봐야 한다. recall 0.8에서 100,000 QPS는 recall 0.99에서 10,000 QPS보다 "빠른 것"이 아니라 "부정확한 것"일 수 있다.


실전 튜닝 워크플로

1
정답 셋(Ground Truth) 준비 대표 쿼리 1,000~10,000개 샘플링 FLAT 인덱스로 정확한 Top-K 계산 필터 조건이 있다면 필터 포함한 정답 셋 구성
2
파라미터 스윕 HNSW: ef = [32, 64, 128, 256, 512] IVF: nprobe = [1, 8, 16, 32, 64, 128] 각 설정에서 Recall@K 와 P99 지연 동시 측정
3
Pareto 최적점 선택 목표 Recall (예: 0.95) 달성 최소 ef 확인 그 설정에서 P99 지연이 SLO 이내인지 확인 지연 초과 시: 인덱스 타입·양자화 재검토
4
부하 테스트로 QPS 상한 파악 선택된 파라미터로 동시 접속 수 증가 P99 지연이 SLO 초과하는 임계 QPS 측정 Recall이 부하 하에서도 유지되는지 확인
벡터 검색 성능 튜닝 워크플로

필터링과 Recall

필터 조건이 포함된 벡터 검색(Filtered ANN)은 별도로 처리해야 한다.

문제: 필터 비율에 따른 Recall 저하

전체 1억 벡터, 필터로 100만 벡터만 대상 (1% 선택성)

IVF_FLAT, nprobe=64:
  → 탐색 클러스터의 99%가 필터에서 탈락
  → 실제 후보가 거의 없어 Recall 급락

HNSW:
  → 필터 인식 그래프가 없으면 동일 문제 발생
  → 필터 인식 HNSW(Qdrant 방식) 또는 pre-filtering 필요

대응 전략

선택성권장 전략
높음 (>50%)필터 후 ANN (post-filtering)
중간 (5~50%)엔진별 필터 인식 ANN 또는 과샘플링(nprobe↑, ef↑)
낮음 (<5%)Pre-filtering: 인덱스 자체를 서브셋으로 분리

Recall 측정 시: 필터 조건을 포함한 정답 셋을 별도로 만들어야 한다. 필터 없는 정답 셋 기준으로 Recall을 측정하면 필터 대응 품질을 알 수 없다.


양자화와 Recall

양자화는 메모리를 줄이는 대신 Recall을 일부 희생한다. 재순위(Rescore/Oversampling)로 대부분 회복 가능하다.

방법압축Recall 손실 (재순위 없이)재순위 후 Recall
SQ8 (int8)1~2%p≈ 원본
BQ (1bit)32×10~30%p원본의 95~99%
PQ (x16)16×5~15%p원본의 92~98%

재순위는 oversampling × K개 후보를 양자화 인덱스로 뽑은 뒤 원본 float32 벡터로 재계산한다. oversampling = 2~3이 실용적 기본값이다.


흔한 실수와 대응

실수결과대응
Recall을 측정하지 않고 QPS만 비교부정확한 검색 서비스모든 성능 측정에 Recall 함께 기록
개발 데이터로 튜닝 후 프로덕션 적용분포 차이로 Recall 하락프로덕션 샘플로 별도 벤치마킹
ef_search를 매우 높게 고정불필요한 지연목표 Recall 달성 최소값으로 설정
필터 조건 변경 후 Recall 재확인 안 함조용한 품질 저하필터 변경 시 Recall 회귀 테스트
인덱스 타입만 바꾸고 파라미터 재조정 안 함서브옵티멀 결과인덱스 변경 시 항상 전체 파라미터 재스윕

References