벡터 데이터베이스 완전 비교 - Chroma, Milvus, Pinecone, Qdrant, Weaviate, pgvector
주요 벡터 데이터베이스의 아키텍처, 설치, 성능, 인덱싱, 하이브리드 검색, 확장성, 선택 가이드를 종합 비교합니다. RAG와 AI 애플리케이션에 최적의 벡터 DB를 선택하세요.
"내 문서에서 의미가 비슷한 내용을 찾아줘" — 일반 데이터베이스에 이런 요청을 하면 어떻게 될까요? LIKE 검색은 정확한 키워드가 있어야만 작동합니다. 하지만 사람은 "같은 말도 다르게 표현"하죠. 벡터 데이터베이스는 바로 이 문제를 풀기 위해 등장했습니다.
벡터 데이터베이스는 RAG, 시맨틱 검색, 추천 시스템 등 AI 애플리케이션의 핵심 인프라입니다. 이 글에서는 6개 주요 벡터 DB의 아키텍처, 성능, 기능을 체계적으로 비교합니다.
이 글에서 배우는 것
- 벡터 데이터베이스가 왜 필요한지, 일반 DB와 무엇이 다른지
- Chroma·Pinecone·Milvus·Qdrant·Weaviate·pgvector의 아키텍처 차이
- 각 DB를 Python으로 빠르게 시작하는 방법
- 인덱싱 알고리즘(HNSW·IVF 등)의 특성
- 내 상황에 맞는 벡터 DB를 고르는 의사결정 흐름
1. 벡터 데이터베이스 개요
벡터 데이터베이스란
텍스트·이미지·오디오를 숫자 배열(벡터)로 변환하면 "의미가 비슷한 것끼리 숫자도 비슷해집니다." 벡터 데이터베이스는 이 고차원 벡터(임베딩)를 효율적으로 저장, 인덱싱, 검색하는 데 특화된 데이터베이스입니다. 의미적 유사도 기반으로 검색합니다.
왜 벡터 데이터베이스가 필요한가
"분산 처리"를 검색하면 "병렬 컴퓨팅"이라는 표현을 쓴 문서도 찾아줘야 하지 않을까요? 일반 DB는 그걸 못 합니다. 아래 비교를 보면 두 세계의 차이가 선명하게 드러납니다.
| 전통 DB 검색 | 벡터 DB 검색 |
|---|---|
| 키워드 일치 (LIKE '%검색어%') | 의미적 유사도 기반 |
| "분산 처리"로 검색 → "분산 처리" 포함 문서만 | "분산 처리"로 검색 → "병렬 컴퓨팅", "클러스터 연산" 포함 문서도 반환 |
| 정확한 키워드가 필요 | 의미가 같으면 다른 표현도 검색 |
| B-Tree, Hash 인덱스 | HNSW, IVF, PQ 인덱스 |
핵심 개념
용어가 낯설게 느껴질 수 있습니다. 지금 당장 전부 외울 필요는 없고, 나중에 코드를 보면서 떠올릴 수 있도록 한 번 훑어두면 충분합니다.
| 개념 | 설명 |
|---|---|
| 임베딩 (Embedding) | 텍스트/이미지를 고차원 벡터로 변환한 수치 표현 |
| 유사도 (Similarity) | 벡터 간 거리/각도로 측정한 의미적 유사성 |
| ANN (Approximate Nearest Neighbor) | 정확도를 약간 희생하여 빠르게 유사 벡터를 찾는 알고리즘 |
| 컬렉션 (Collection) | 동일 스키마의 벡터를 모은 논리적 그룹 (테이블에 해당) |
| 메타데이터 (Metadata) | 벡터에 첨부된 필터링용 속성 정보 |
2. 아키텍처 비교
각 DB의 구조를 간략히 살펴봅니다. 아키텍처를 이해하면 "왜 이 DB는 빠른가, 왜 이 DB는 대규모에 강한가"가 자연스럽게 납득됩니다.
Chroma — 경량 임베디드
- 유형: 임베디드 (in-process) 또는 클라이언트-서버
- 언어: Python
- 스토리지: SQLite + DuckDB
- 적합: 프로토타입, PoC, 소규모 (< 100만 벡터)
Pinecone — 완전 관리형 SaaS
- 유형: 관리형 SaaS (자체 호스팅 불가)
- 스토리지: 자체 분산 스토리지
- 적합: 운영 부담 최소화, 빠른 구축, 중대규모
Milvus — 클라우드 네이티브 분산
- 유형: 분산 (Kubernetes 기반)
- 언어: Go + C++
- 적합: 엔터프라이즈 대규모 (수십억 벡터), GPU 인덱싱
Qdrant — 고성능 Rust 기반
- 유형: 단일 노드 또는 분산 클러스터
- 언어: Rust
- 적합: 고성능 필터링, 중대규모, 낮은 지연시간
Weaviate — 하이브리드 검색 특화
- 유형: 단일 노드 또는 분산
- 언어: Go
- 적합: 하이브리드 검색 (벡터 + 키워드) 중심, 내장 임베딩
pgvector — PostgreSQL 확장
- 유형: PostgreSQL 확장 (기존 DB 활용)
- 언어: C
- 적합: 이미 PostgreSQL을 사용하는 환경, 소중규모
아키텍처 비교 요약
한 문장으로: 프로토타입이면 Chroma, 프로덕션이면 상황에 따라 Milvus·Qdrant·Weaviate 중 하나를 고르면 됩니다.
| 항목 | Chroma | Pinecone | Milvus | Qdrant | Weaviate | pgvector |
|---|---|---|---|---|---|---|
| 배포 모델 | 임베디드/서버 | SaaS | 분산 (K8s) | 단일/분산 | 단일/분산 | DB 확장 |
| 핵심 언어 | Python | - | Go/C++ | Rust | Go | C |
| 수평 확장 | X | O (자동) | O | O | O | 제한적 |
| GPU 지원 | X | - | O | X | X | X |
| 오픈소스 | O (Apache 2.0) | X | O (Apache 2.0) | O (Apache 2.0) | O (BSD-3) | O (PostgreSQL) |
| 최대 벡터 수 | 수백만 | 수십억 | 수백억 | 수십억 | 수십억 | 수백만 |
3. 설치와 빠른 시작
말보다 코드가 빠릅니다. 각 DB를 실제로 써보는 가장 짧은 예시를 모아뒀습니다. 여러분의 프로젝트에 맞는 DB를 고른 뒤, 해당 섹션의 코드를 복사해서 바로 실행해보세요.
Chroma
pip install chromadbimport chromadb
client = chromadb.Client() # 인메모리
# client = chromadb.PersistentClient(path="./chroma_db") # 영구 저장
collection = client.create_collection("documents")
collection.add(
ids=["doc1", "doc2", "doc3"],
documents=[
"Apache Spark는 분산 데이터 처리 프레임워크입니다",
"Kafka는 분산 이벤트 스트리밍 플랫폼입니다",
"Kubernetes는 컨테이너 오케스트레이션 도구입니다"
],
metadatas=[
{"category": "compute"},
{"category": "messaging"},
{"category": "orchestration"}
]
)
results = collection.query(
query_texts=["대용량 데이터 병렬 처리"],
n_results=2
)
print(results["documents"])Pinecone
pip install pineconefrom pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="documents",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
index = pc.Index("documents")
index.upsert(vectors=[
{"id": "doc1", "values": [0.1, 0.2, ...], "metadata": {"category": "compute"}},
{"id": "doc2", "values": [0.3, 0.4, ...], "metadata": {"category": "messaging"}},
])
results = index.query(
vector=[0.1, 0.2, ...],
top_k=3,
include_metadata=True,
filter={"category": {"$eq": "compute"}}
)Milvus
# Docker로 실행
docker compose up -d # docker-compose.yml 필요
pip install pymilvusfrom pymilvus import MilvusClient
client = MilvusClient(uri="http://localhost:19530")
client.create_collection(
collection_name="documents",
dimension=1536,
metric_type="COSINE"
)
data = [
{"id": 1, "vector": [0.1, 0.2, ...], "text": "Spark는...", "category": "compute"},
{"id": 2, "vector": [0.3, 0.4, ...], "text": "Kafka는...", "category": "messaging"},
]
client.insert(collection_name="documents", data=data)
results = client.search(
collection_name="documents",
data=[[0.1, 0.2, ...]],
limit=3,
output_fields=["text", "category"]
)Qdrant
docker run -p 6333:6333 qdrant/qdrant
pip install qdrant-clientfrom qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance, PointStruct
client = QdrantClient(host="localhost", port=6333)
client.create_collection(
collection_name="documents",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)
client.upsert(
collection_name="documents",
points=[
PointStruct(id=1, vector=[0.1, 0.2, ...], payload={"category": "compute", "text": "Spark는..."}),
PointStruct(id=2, vector=[0.3, 0.4, ...], payload={"category": "messaging", "text": "Kafka는..."}),
]
)
results = client.search(
collection_name="documents",
query_vector=[0.1, 0.2, ...],
limit=3,
query_filter={"must": [{"key": "category", "match": {"value": "compute"}}]}
)Weaviate
docker run -p 8080:8080 -p 50051:50051 semitechnologies/weaviate
pip install weaviate-clientimport weaviate
client = weaviate.connect_to_local()
collection = client.collections.create(
name="Document",
vectorizer_config=weaviate.classes.config.Configure.Vectorizer.none(),
properties=[
weaviate.classes.config.Property(name="text", data_type=weaviate.classes.config.DataType.TEXT),
weaviate.classes.config.Property(name="category", data_type=weaviate.classes.config.DataType.TEXT),
]
)
collection.data.insert_many([
{"text": "Spark는 분산 데이터 처리 프레임워크입니다", "category": "compute"},
{"text": "Kafka는 분산 이벤트 스트리밍 플랫폼입니다", "category": "messaging"},
])
results = collection.query.near_vector(
near_vector=[0.1, 0.2, ...],
limit=3,
return_metadata=weaviate.classes.query.MetadataQuery(distance=True)
)pgvector
-- PostgreSQL에 pgvector 확장 설치
CREATE EXTENSION vector;
-- 테이블 생성
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
text TEXT,
category TEXT,
embedding vector(1536)
);
-- 인덱스 생성 (HNSW)
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);
-- 데이터 삽입
INSERT INTO documents (text, category, embedding)
VALUES ('Spark는 분산 처리 프레임워크입니다', 'compute', '[0.1, 0.2, ...]');
-- 유사도 검색
SELECT text, category, 1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 3;4. 인덱싱 알고리즘
벡터 DB에서 "빠른 검색"을 가능하게 하는 비결이 인덱싱 알고리즘입니다. 지도를 쓸 때 전체 도시를 샅샅이 다니지 않고 대로를 따라 목적지로 가는 것처럼, ANN 알고리즘은 정확도를 조금 타협하는 대신 훨씬 빠르게 유사 벡터를 찾아줍니다.
알고리즘 비교
| 알고리즘 | 원리 | 검색 속도 | 정확도 (Recall) | 메모리 | 빌드 시간 |
|---|---|---|---|---|---|
| Flat | 전수 비교 | 매우 느림 | 100% | 낮음 | 없음 |
| HNSW | 계층적 그래프 | 매우 빠름 | 95~99% | 높음 | 중간 |
| IVF-Flat | 클러스터 + 전수 | 빠름 | 90~98% | 중간 | 빠름 |
| IVF-PQ | 클러스터 + 양자화 | 매우 빠름 | 85~95% | 매우 낮음 | 빠름 |
| SCANN | Google 최적화 | 매우 빠름 | 95~99% | 중간 | 중간 |
DB별 인덱스 지원
| 인덱스 | Chroma | Pinecone | Milvus | Qdrant | Weaviate | pgvector |
|---|---|---|---|---|---|---|
| HNSW | O (기본) | - (내부) | O | O (기본) | O (기본) | O |
| IVF-Flat | X | - | O | X | X | O |
| IVF-PQ | X | - | O | X | X | X |
| GPU 인덱스 | X | - | O | X | X | X |
| 동적 인덱스 | O | O | O | O | O | X (재빌드) |
참고: 대부분의 사용 사례에서 HNSW가 최적의 선택입니다. Recall 95%+ 에서도 빠른 검색 속도를 제공합니다. 10억+ 벡터의 초대규모에서는 IVF-PQ나 GPU 인덱스를 고려하세요.
5. 검색 기능
유사도 메트릭
두 벡터가 "얼마나 비슷한가"를 재는 방법은 여러 가지입니다. 대부분의 경우 Cosine 유사도가 잘 작동하며, 특히 임베딩 모델을 통해 정규화된 벡터라면 거의 항상 Cosine을 선택하면 됩니다.
| 메트릭 | 수식 | 범위 | 적합 상황 |
|---|---|---|---|
| Cosine | cos(θ) = A·B / (‖A‖·‖B‖) | -1 ~ 1 | 정규화된 임베딩 (대부분의 경우) |
| L2 (Euclidean) | √Σ(ai - bi)² | 0 ~ ∞ | 거리 기반 비교 |
| Inner Product | Σ(ai × bi) | -∞ ~ ∞ | 정규화된 벡터 시 Cosine과 동일 |
메타데이터 필터링
"엔지니어링 카테고리 문서 중에서 2025년 이후의 것만 찾아줘" — 이런 요청처럼 벡터 검색에 조건을 함께 걸어야 할 때 메타데이터 필터링이 필요합니다. Qdrant는 이 부분에서 특히 강력합니다.
# Qdrant: 강력한 필터링 예시
from qdrant_client.models import Filter, FieldCondition, MatchValue, Range
results = client.search(
collection_name="documents",
query_vector=query_vector,
limit=5,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="engineering")),
FieldCondition(key="date", range=Range(gte="2025-01-01")),
],
must_not=[
FieldCondition(key="status", match=MatchValue(value="archived")),
]
)
)하이브리드 검색 (벡터 + 키워드)
의미 검색(벡터)과 키워드 검색(BM25)을 함께 쓰면 각각의 약점을 보완할 수 있습니다. Weaviate는 이 하이브리드 검색을 가장 자연스럽게 지원합니다. alpha 값으로 두 방식의 비중을 조절하면 됩니다.
# Weaviate: 네이티브 하이브리드 검색
results = collection.query.hybrid(
query="Spark 성능 최적화", # BM25 키워드 검색
vector=[0.1, 0.2, ...], # 벡터 검색
alpha=0.7, # 0=키워드만, 1=벡터만, 0.7=벡터 70%
limit=5
)DB별 검색 기능 비교
| 기능 | Chroma | Pinecone | Milvus | Qdrant | Weaviate | pgvector |
|---|---|---|---|---|---|---|
| 벡터 검색 | O | O | O | O | O | O |
| 메타데이터 필터 | O (기본) | O | O | O (강력) | O | O (SQL) |
| 하이브리드 검색 | X | O (Sparse) | O | O (Sparse) | O (네이티브) | X |
| 멀티벡터 | X | O (Namespace) | O | O (Named) | O | O (다중 컬럼) |
| 전문 검색 (Full-text) | X | X | X | O | O (BM25) | O (tsvector) |
| 필터+검색 동시 | O | O | O | O (Pre-filter) | O | O |
6. 확장성과 성능
벤치마크 비교 (참고용)
| 지표 | Chroma | Pinecone | Milvus | Qdrant | Weaviate | pgvector |
|---|---|---|---|---|---|---|
| 삽입 속도 (1M벡터) | ~5분 | ~3분 | ~2분 | ~2분 | ~4분 | ~8분 |
| 쿼리 지연 (p99) | ~15ms | ~10ms | ~8ms | ~5ms | ~12ms | ~20ms |
| 동시 쿼리 (QPS) | ~500 | ~3,000 | ~5,000 | ~4,000 | ~2,000 | ~300 |
| 최대 벡터 수 | 수백만 | 수십억 | 수백억 | 수십억 | 수십억 | 수백만 |
참고: 위 수치는 참고용이며, 하드웨어, 벡터 차원, 인덱스 설정에 따라 크게 달라집니다. 실제 환경에서의 벤치마크를 권장합니다.
수평 확장
| DB | 수평 확장 | 방식 | 최소 구성 |
|---|---|---|---|
| Chroma | X | - | 단일 프로세스 |
| Pinecone | O (자동) | 관리형 | API 키만 필요 |
| Milvus | O | K8s 기반 샤딩/복제 | etcd + MinIO + Pulsar |
| Qdrant | O | Raft 기반 클러스터 | 3+ 노드 |
| Weaviate | O | 자체 클러스터링 | 3+ 노드 |
| pgvector | 제한적 | PostgreSQL 복제 | 리드 레플리카 |
7. 엔터프라이즈 기능
| 기능 | Chroma | Pinecone | Milvus | Qdrant | Weaviate | pgvector |
|---|---|---|---|---|---|---|
| 인증/인가 | X | O (API Key) | O (RBAC) | O (API Key) | O (OIDC) | O (PostgreSQL) |
| 백업/복원 | 파일 복사 | O (자동) | O (Milvus Backup) | O (스냅샷) | O | O (pg_dump) |
| 모니터링 | 기본 | O (대시보드) | O (Grafana) | O (Prometheus) | O (Prometheus) | O (pg_stat) |
| 멀티테넌시 | 컬렉션 분리 | O (Namespace) | O (파티션) | O (Payload 필터) | O (테넌트) | O (스키마) |
| 클라우드 관리형 | X | O (핵심) | O (Zilliz) | O (Qdrant Cloud) | O (Weaviate Cloud) | O (각 클라우드 DB) |
8. AI 프레임워크 연동
LangChain 연동
# Chroma
from langchain_chroma import Chroma
vectorstore = Chroma.from_documents(docs, embeddings, persist_directory="./db")
# Pinecone
from langchain_pinecone import PineconeVectorStore
vectorstore = PineconeVectorStore.from_documents(docs, embeddings, index_name="my-index")
# Milvus
from langchain_milvus import Milvus
vectorstore = Milvus.from_documents(docs, embeddings, connection_args={"host": "localhost", "port": "19530"})
# Qdrant
from langchain_qdrant import QdrantVectorStore
vectorstore = QdrantVectorStore.from_documents(docs, embeddings, url="http://localhost:6333", collection_name="docs")
# Weaviate
from langchain_weaviate import WeaviateVectorStore
vectorstore = WeaviateVectorStore.from_documents(docs, embeddings, client=weaviate_client)
# pgvector
from langchain_postgres import PGVector
vectorstore = PGVector.from_documents(docs, embeddings, connection="postgresql://...", collection_name="docs")RAG 파이프라인에서의 활용
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# 어떤 벡터 DB든 동일한 RAG 체인
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
prompt = ChatPromptTemplate.from_template("""
컨텍스트를 참고하여 질문에 답하세요.
컨텍스트: {context}
질문: {question}
""")
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI(model="gpt-4o")
| StrOutputParser()
)
answer = rag_chain.invoke("Spark 성능 최적화 방법은?")9. 선택 가이드
의사결정 플로차트
"어떤 벡터 DB를 써야 하나요?" 에 대한 체계적인 답입니다. 아래 흐름을 따라가면 대부분의 상황에서 좋은 선택에 도달할 수 있습니다.
시나리오별 추천
플로차트가 번거롭다면 아래 표에서 여러분의 상황과 가장 비슷한 행을 바로 찾아보세요.
| 시나리오 | 추천 | 이유 |
|---|---|---|
| RAG 프로토타입 빠르게 만들기 | Chroma | 설치 없이 pip만으로 즉시 사용 |
| 기존 PostgreSQL에 벡터 검색 추가 | pgvector | 추가 인프라 불필요, SQL로 통합 쿼리 |
| 스타트업에서 빠르게 프로덕션 배포 | Pinecone | 운영 부담 제로, 자동 확장 |
| 엔터프라이즈 대규모 문서 검색 | Milvus | 수십억 벡터 지원, GPU 인덱싱 |
| 복잡한 필터 + 벡터 검색 조합 | Qdrant | Rust 기반 고성능 필터링 |
| 키워드 + 벡터 하이브리드 검색 | Weaviate | BM25 + 벡터 네이티브 하이브리드 |
| 온프레미스 + Kubernetes 환경 | Milvus 또는 Qdrant | K8s Helm 차트 제공, 자체 호스팅 |
| 다국어 검색 시스템 | Weaviate | 내장 벡터라이저, 다국어 모듈 |
참고: 벡터 DB 선택은 "최고의 DB"를 찾는 것이 아니라 "우리 환경에 가장 적합한 DB"를 찾는 것입니다. 프로토타입은 Chroma로 시작하고, 프로덕션 요구사항이 확정되면 전환하는 전략이 효과적입니다.
마치며 — 핵심 요약
- 벡터 DB는 "의미가 비슷한 것을 찾는" 검색에 특화되어 있습니다. 키워드 검색의 한계를 뛰어넘어 RAG와 시맨틱 검색의 기반이 됩니다.
- 처음 시작하는 프로젝트라면 Chroma로 시작하세요 — pip 하나로 설치되고 인프라가 필요 없습니다.
- 기존에 PostgreSQL을 쓰고 있다면 pgvector를 먼저 시도해보세요. 추가 인프라 없이 SQL과 통합됩니다.
- 프로덕션 규모가 되면 요구사항에 따라 나뉩니다 — 대규모 분산은 Milvus, 정교한 필터링은 Qdrant, 하이브리드 검색은 Weaviate, 운영 부담 제로는 Pinecone.
- 대부분의 사용 사례에서 HNSW 인덱스가 가장 좋은 선택입니다. 10억 벡터 이상의 초대규모에서만 IVF-PQ나 GPU 인덱스를 고려하세요.
- LangChain과 연동할 때는 어떤 벡터 DB를 써도 동일한 인터페이스(
as_retriever())로 RAG 체인에 연결할 수 있어 나중에 전환도 어렵지 않습니다.
References
- Chroma Documentation — https://docs.trychroma.com/
- Pinecone Documentation — https://docs.pinecone.io/
- Milvus Documentation — https://milvus.io/docs
- Qdrant Documentation — https://qdrant.tech/documentation/
- Weaviate Documentation — https://weaviate.io/developers/weaviate
- pgvector GitHub — https://github.com/pgvector/pgvector
- Malkov, Y. & Yashunin, D. (2020). "Efficient and Robust Approximate Nearest Neighbor using Hierarchical Navigable Small World Graphs." IEEE TPAMI
— Data Dynamics 엔지니어링 팀