프로덕션 벡터 DB 선택 2026: pgvector 0.8 vs Qdrant 1.18 스케일·비용 실전 가이드
pgvector 0.8.2와 Qdrant 1.18(TurboQuant)을 기준으로 RAG 벡터 DB를 규모·지연·비용 관점에서 선택하고 운영하는 실전 가이드입니다.
목차
RAG 파이프라인을 프로토타입에서 프로덕션으로 옮기는 순간 가장 먼저 무너지는 곳이 벡터 검색 계층입니다. 임베딩이 100만 건을 넘어가면 인덱스 빌드 시간, p99 지연, 메모리 비용이 동시에 폭증하고, "일단 Postgres에 넣자"던 결정이 발목을 잡기 시작합니다. 이 글에서는 2026년 6월 기준 최신 릴리스인 pgvector 0.8.2와 Qdrant 1.18을 놓고, 규모 구간별로 무엇을 골라야 하는지, 그리고 양쪽을 어떻게 튜닝해야 비용이 절반으로 떨어지는지를 정리합니다.
왜 지금 다시 벡터 DB 선택을 고민해야 하나
2024~2025년에는 "벡터 DB는 다 비슷하다"는 인식이 있었지만, 2026년 들어 두 진영이 확실히 갈렸습니다. 한쪽은 이미 Postgres를 쓰는 팀을 위한 pgvector가 0.8 계열에서 필터링 검색의 고질병을 해결하며 프로덕션 신뢰도를 끌어올렸고, 다른 한쪽은 전용 엔진 Qdrant가 1.18의 TurboQuant 양자화로 메모리 비용을 기존 대비 절반 이하로 줄였습니다. 선택 기준이 "성능 좋은 것"에서 "우리 데이터 플랫폼·규모·비용 구조에 맞는 것"으로 바뀐 것입니다.
핵심 판단은 단순합니다. 이미 Postgres가 데이터 플랫폼의 중심이라면 pgvector가 기본값이고, 별도 벡터 엔진은 규모나 워크로드가 그것을 정당화할 때만 도입합니다. Postgres가 없거나 수천만 건 이상을 다룬다면 Qdrant 같은 전용 엔진이 운영 효율에서 앞섭니다.
2026년 현황: 무엇이 바뀌었나
두 엔진의 최신 릴리스에서 실무에 직접 영향을 주는 변경점은 다음과 같습니다.
| 항목 | pgvector 0.8.2 (2026.02) | Qdrant 1.18 (2026.05) |
|---|---|---|
| 인덱스 | HNSW, IVFFlat | HNSW |
| 필터링 검색 | iterative_scan (off/strict/relaxed) | 페이로드 인덱스 + 필터러블 HNSW |
| 양자화 | binary, halfvec(2바이트) | Scalar(4x), Binary(최대 32x), TurboQuant |
| 최신 압축 | sparsevec, halfvec | TurboQuant 8x/16x/21x/32x |
| 권장 규모 | ~1천만 벡터 (Postgres 동거) | 1천만~10억+ (분산) |
| p50 지연(전용 벤치) | 28ms대(pgvectorscale) | 약 4ms |
| 운영 모델 | Postgres 확장 = 단일 스택 | 별도 클러스터 |
여기서 가장 중요한 두 가지는 pgvector의 iterative_scan과 Qdrant의 TurboQuant입니다. 전자는 "WHERE 조건 + 벡터 검색"을 동시에 걸었을 때 결과가 부족하게 반환되던 오버필터링 문제를 해결했고, 후자는 1비트 이진 양자화보다 같은 저장 예산에서 더 높은 재현율을 제공합니다.
심층 분석: 핵심 설정을 코드로
pgvector — HNSW 인덱스와 필터링 검색
100만 건 이상이라면 IVFFlat보다 HNSW가 사실상 기본 선택입니다. halfvec로 차원당 2바이트를 쓰면 저장 공간이 절반으로 줄고 재현율 손실은 미미합니다.
-- 1) 테이블: 1536차원 임베딩을 halfvec로 저장 (저장공간 절반)
CREATE TABLE documents (
id bigserial PRIMARY KEY,
tenant_id bigint NOT NULL,
body text,
embedding halfvec(1536) -- ⚠️ vector 대신 halfvec
);
-- 2) HNSW 인덱스 (halfvec 전용 연산자 클래스)
CREATE INDEX ON documents
USING hnsw (embedding halfvec_cosine_ops)
WITH (m = 16, ef_construction = 64); -- 빌드는 병렬, 30~50% 단축
-- 3) 필터링 검색 시 오버필터링 방지 (0.8 신규)
SET hnsw.iterative_scan = 'relaxed_order'; -- 성능 우선
SET hnsw.ef_search = 100; -- 재현율 손잡이
SELECT id, body
FROM documents
WHERE tenant_id = 42 -- 필터 + 벡터 동시
ORDER BY embedding <=> $1::halfvec
LIMIT 10;
iterative_scan은 off(기본·전통 동작), strict_order(정확한 거리 정렬 유지), relaxed_order(근사 정렬, 성능 우선) 세 가지 모드를 제공합니다. 멀티테넌트처럼 필터 선택도가 높은 워크로드에서는 relaxed_order가 지연과 재현율의 균형이 좋습니다.
Qdrant — TurboQuant로 메모리 비용 절감
Qdrant는 원본 벡터를 디스크에 두고 양자화 벡터만 메모리에 올린 뒤, 후보를 재정렬(rescore)하는 구조로 메모리를 절약합니다. 1.18의 TurboQuant는 압축 전 빠른 랜덤 회전을 적용해 좌표를 고르게 재분포시키는 방식으로, 같은 저장 예산에서 이진 양자화보다 재현율이 높습니다.
# Qdrant 1.18: TurboQuant 기반 컬렉션 생성
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://qdrant:6333")
client.create_collection(
collection_name="documents",
vectors_config=models.VectorParams(
size=1536,
distance=models.Distance.COSINE,
on_disk=True, # 원본 벡터는 디스크
),
quantization_config=models.BinaryQuantization(
binary=models.BinaryQuantizationConfig(
always_ram=True, # 양자화 벡터는 RAM 상주
),
),
)
# 검색: oversampling으로 후보를 넓게 뽑고 원본으로 재정렬
hits = client.query_points(
collection_name="documents",
query=query_vector,
limit=10,
search_params=models.SearchParams(
quantization=models.QuantizationSearchParams(
rescore=True, # 원본 재정렬로 정확도 회복
oversampling=2.0, # 후보 2배 확보
)
),
).points
TurboQuant는 8x(4비트/차원), 16x(2비트/차원), 약 21x(1.5비트/차원), 32x(1비트/차원) 네 가지 운영점을 제공합니다. 정확도가 중요하면 8x, 메모리 압박이 심하면 32x를 시작점으로 두고 oversampling으로 재현율을 보정합니다.
페이로드 필터링 — 두 엔진의 사고방식 차이
같은 "메타데이터 필터 + 벡터" 검색이라도 접근이 다릅니다. pgvector는 SQL WHERE로 자연스럽게 통합되고, Qdrant는 페이로드 인덱스를 명시적으로 만들어 필터러블 HNSW를 활용합니다.
# Qdrant: 페이로드 인덱스 생성 후 필터 검색
client.create_payload_index(
collection_name="documents",
field_name="tenant_id",
field_schema=models.PayloadSchemaType.INTEGER,
)
hits = client.query_points(
collection_name="documents",
query=query_vector,
query_filter=models.Filter(
must=[models.FieldCondition(
key="tenant_id",
match=models.MatchValue(value=42),
)]
),
limit=10,
).points
실전 가이드: 규모 구간별 선택과 적용
실무에서는 다음 순서로 결정하면 대부분 맞아떨어집니다.
- 1천만 벡터 미만: 거의 모든 엔진이 충분합니다. 이미 Postgres를 쓴다면 pgvector로 단일 스택을 유지하는 편이 운영 비용 면에서 압도적으로 유리합니다.
- 1천만~10억 벡터: 전용 엔진 영역입니다. Qdrant·Weaviate·Milvus 중 운영 친숙도로 고르되, 메모리 비용이 부담이면 Qdrant 양자화가 강력합니다.
- 10억 벡터 초과: Milvus·Vespa의 분산 배포가 사실상 유일한 프로덕션 선택지입니다.
pgvector 적용 단계는 다음과 같습니다.
# Postgres 18 + pgvector 0.8.2 확장 활성화
psql -c "CREATE EXTENSION IF NOT EXISTS vector;"
psql -c "SELECT extversion FROM pg_extension WHERE extname='vector';" # 0.8.2 확인
# 대량 적재 후 인덱스 생성 (적재 전 인덱스 생성은 느림)
psql -c "SET maintenance_work_mem = '2GB'; SET max_parallel_maintenance_workers = 4;"
Qdrant는 컨테이너로 띄우고 스냅샷으로 백업을 자동화합니다.
docker run -d --name qdrant -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant:v1.18.0
# 컬렉션 스냅샷(백업)
curl -X POST http://localhost:6333/collections/documents/snapshots
트러블슈팅: 자주 만나는 세 가지 문제
필터를 걸면 결과가 LIMIT보다 적게 나옵니다. pgvector 0.7 이하에서 흔한 오버필터링입니다. 0.8로 올린 뒤 hnsw.iterative_scan을 relaxed_order로 켜고, 그래도 부족하면 hnsw.ef_search를 100~200으로 올리세요.
Qdrant 메모리가 예상보다 큽니다. 양자화를 켰는데도 원본 벡터가 RAM에 남아 있는 경우입니다. on_disk=True로 원본을 디스크에 두고, 양자화 벡터만 always_ram=True로 상주시키면 RAM 사용량이 크게 줄어듭니다. 정확도가 떨어지면 rescore=True와 oversampling을 함께 조정합니다.
HNSW 인덱스 빌드가 너무 오래 걸립니다. pgvector는 max_parallel_maintenance_workers와 maintenance_work_mem을 늘리면 멀티코어에서 빌드 시간이 30~50% 단축됩니다. 대량 적재는 반드시 데이터를 먼저 넣고 인덱스를 마지막에 생성하세요. 행마다 인덱스를 갱신하는 것보다 훨씬 빠릅니다.
결론: 스택의 무게중심으로 결정하라
벡터 DB 선택은 벤치마크 숫자가 아니라 데이터 플랫폼의 무게중심과 규모 구간으로 결정해야 합니다. Postgres 중심이고 1천만 건 이하라면 pgvector 0.8.2가 운영·비용 모두에서 정답에 가깝고, 그 이상이거나 메모리 비용이 핵심 제약이라면 Qdrant 1.18의 양자화가 강력한 무기가 됩니다.
IntentCode는 고객의 RAG 시스템을 설계할 때 이 선택을 비즈니스 규모와 비용 곡선에 맞춰 처음부터 분리합니다 — 초기엔 pgvector로 단일 스택을 유지하다가, 트래픽과 임베딩 규모가 임계점을 넘으면 Qdrant 기반 전용 검색 계층으로 무중단 전환하는 마이그레이션 경로까지 함께 제공합니다.