Skip to content

필사 모드: Vector DB 완전 비교 2025: Pinecone, Weaviate, Chroma, pgvector 중 무엇을 선택하는가

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

RAG 시스템을 구축하다 보면 필연적으로 벡터 데이터베이스를 선택해야 하는 순간이 온다. Pinecone, Weaviate, Chroma, pgvector, Qdrant... 선택지가 너무 많다.

각 도구는 다른 상황을 위해 최적화되어 있다. 프로토타입을 빠르게 만들어야 하는 상황과 수억 개의 벡터를 처리해야 하는 프로덕션 환경은 완전히 다른 선택이 필요하다. 이 글에서 실용적 기준으로 각 DB를 비교하고 결정 프레임워크를 제시한다.

벡터 DB가 왜 필요한가?

일반 데이터베이스와의 차이를 이해하면 벡터 DB의 가치가 명확해진다.

-- 일반 DB: 정확한 매칭

SELECT * FROM products WHERE id = 123;

SELECT * FROM documents WHERE title = '인공지능 가이드';

-- 벡터 DB: 의미적 유사도 검색

-- "AI에 대해 알려줘" 쿼리 → 가장 관련 있는 문서 5개 반환

SELECT id, content, 1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity

FROM documents

ORDER BY embedding <=> '[0.1, 0.2, ...]'

LIMIT 5;

-- "=" 연산이 아닌 "<=> (코사인 거리)" 연산

벡터 DB는 수백만 개의 고차원 벡터에서 "가장 가까운 이웃"을 밀리초 내에 찾아주도록 특화되어 있다.

핵심 알고리즘: HNSW vs IVF

벡터 DB를 이해하려면 핵심 인덱싱 알고리즘을 알아야 한다.

HNSW (Hierarchical Navigable Small World):

─────────────────────────────────────────

구조: 계층적 그래프 (마치 지도의 줌 레벨처럼)

빌드 시간: O(n log n)

쿼리 시간: O(log n) 근사

메모리: 높음 (전체 그래프를 RAM에 유지)

정확도: 높음 (조정 가능)

장점: 빠른 쿼리, 높은 정확도, 동적 삽입 지원

단점: 메모리 사용량 큼, 빌드 시간 길음

적합: 수백만~수억 건, 높은 recall 요구

IVF (Inverted File Index):

──────────────────────────

구조: k-means 클러스터링 후 각 클러스터를 별도 인덱스로

빌드 시간: 빠름 (클러스터 수만큼)

쿼리 시간: nprobe 파라미터에 의존

메모리: HNSW보다 낮음

정확도: nprobe 증가 시 향상

장점: 메모리 효율적, 수십억 건 처리 가능

단점: 쿼리 시 nprobe 튜닝 필요, 정확도-속도 트레이드오프

적합: 수십억 건 이상의 초대규모 데이터셋

대부분의 RAG 시스템(수백만 건 이하)에서는 HNSW가 더 나은 선택이다.

각 DB 상세 비교

Pinecone: 운영 부담 없는 관리형 SaaS

from pinecone import Pinecone, ServerlessSpec

초기화

pc = Pinecone(api_key="your-api-key")

인덱스 생성 (한 번만)

index = pc.create_index(

name="my-rag-index",

dimension=1536, # 사용하는 임베딩 모델 차원과 일치

metric="cosine", # cosine, euclidean, dotproduct 중 선택

spec=ServerlessSpec(

cloud="aws",

region="us-east-1"

)

)

벡터 업서트 (삽입/업데이트)

index = pc.Index("my-rag-index")

index.upsert(vectors=[

{

"id": "doc1",

"values": embedding_vector,

"metadata": {

"text": "원본 텍스트 내용",

"source": "document.pdf",

"page": 1,

"created_at": "2025-01-01"

}

},

{

"id": "doc2",

"values": embedding_vector2,

"metadata": {"text": "두 번째 문서 내용"}

}

])

유사도 검색

results = index.query(

vector=query_embedding,

top_k=5,

include_metadata=True,

filter={"source": {"$eq": "document.pdf"}} # 메타데이터 필터링

)

for match in results.matches:

print(f"ID: {match.id}, Score: {match.score:.3f}")

print(f"Text: {match.metadata['text'][:100]}")

네임스페이스로 멀티테넌시 구현

index.upsert(

vectors=[...],

namespace="customer-123" # 고객별 격리

)

**장점:**

- 제로 운영: 인프라 관리, 스케일링, 백업 자동

- 초당 수만 건의 쿼리 자동 처리

- 99.99% SLA

**단점:**

- 비용이 비쌈: 1억 벡터 기준 월 $70+ (Serverless), 전용 Pod는 수백~수천 달러

- 데이터가 Pinecone 인프라에 저장됨 (벤더 락인)

- 복잡한 필터링 쿼리에서 성능 저하 가능

**적합한 상황:** 빠른 프로덕션 출시, DevOps 리소스 없음, 비용보다 속도가 중요

Weaviate: 하이브리드 검색의 강자

from weaviate.classes.config import Configure, Property, DataType, VectorDistances

로컬 연결 (Docker로 실행) 또는 Weaviate Cloud Services

client = weaviate.connect_to_local()

또는: client = weaviate.connect_to_wcs(cluster_url="your-url", auth_credentials=...)

스키마 정의 (컬렉션 생성)

client.collections.create(

"Document",

vectorizer_config=Configure.Vectorizer.text2vec_openai(), # 자동 임베딩

vector_index_config=Configure.VectorIndex.hnsw(

distance_metric=VectorDistances.COSINE

),

properties=[

Property(name="content", data_type=DataType.TEXT),

Property(name="source", data_type=DataType.TEXT),

Property(name="page", data_type=DataType.INT)

]

)

문서 삽입 (vectorizer 설정 시 임베딩 자동 생성)

collection = client.collections.get("Document")

collection.data.insert({

"content": "인공지능이 세상을 바꾸고 있다",

"source": "article.pdf",

"page": 1

})

시맨틱 검색

results = collection.query.near_text(

query="AI 기술 동향",

limit=5,

return_metadata=["distance", "score"]

)

하이브리드 검색 (벡터 + BM25 키워드)

hybrid_results = collection.query.hybrid(

query="AI 기술 동향",

alpha=0.5, # 0: 순수 BM25, 1: 순수 벡터, 0.5: 균형

limit=5

)

GraphQL로 복잡한 쿼리

complex_results = collection.query.near_text(

query="AI 기술 동향",

filters=wq.Filter.by_property("page").greater_than(0),

limit=10

)

**장점:**

- 하이브리드 검색(벡터 + 키워드) 내장

- 멀티모달 지원 (텍스트, 이미지, 오디오)

- 자동 벡터화 (vectorizer 설정 시 임베딩 코드 불필요)

- 오픈소스 + 클라우드 모두 지원

**단점:**

- 설정이 복잡하고 리소스 소모가 큼

- Docker 기본 설치 시 2GB+ RAM 필요

- 러닝 커브가 높음

**적합한 상황:** 하이브리드 검색 필요, 자체 인프라 운영 가능, 복잡한 스키마

Chroma: 가장 쉬운 시작점

from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction

인메모리 (개발/테스트용)

client = chromadb.Client()

영구 저장 (로컬 파일)

client = chromadb.PersistentClient(path="./chroma_db")

임베딩 함수 설정 (자동 임베딩)

embedding_fn = OpenAIEmbeddingFunction(

api_key="your-openai-key",

model_name="text-embedding-3-small"

)

collection = client.create_collection(

name="my_documents",

embedding_function=embedding_fn,

metadata={"hnsw:space": "cosine"}

)

문서 추가 (텍스트 제공 시 자동 임베딩)

collection.add(

documents=[

"RAG는 검색 증강 생성 기술입니다",

"임베딩은 텍스트를 벡터로 변환합니다",

"벡터 DB는 유사도 검색에 최적화되어 있습니다"

],

ids=["doc1", "doc2", "doc3"],

metadatas=[

{"source": "guide.pdf", "page": 1},

{"source": "guide.pdf", "page": 2},

{"source": "guide.pdf", "page": 3}

]

)

쿼리 (텍스트만 제공하면 됨)

results = collection.query(

query_texts=["텍스트 검색 기술에 대해 알려주세요"],

n_results=3,

where={"source": "guide.pdf"} # 메타데이터 필터

)

print(results["documents"])

print(results["distances"])

**장점:**

- 가장 쉬운 API, 코드 5줄로 시작 가능

- Python 네이티브, Jupyter에서 바로 실행

- 오픈소스, 무료

**단점:**

- 대규모 프로덕션에 적합하지 않음 (수백만 건 이상에서 성능 저하)

- 분산 처리 미지원

- 엔터프라이즈 기능 부재

**적합한 상황:** 프로토타입, 데모, 개발 환경, 소규모 데이터셋

pgvector: 이미 PostgreSQL을 쓰고 있다면

-- PostgreSQL 확장 설치

CREATE EXTENSION vector;

-- 벡터 컬럼이 있는 테이블 생성

CREATE TABLE documents (

id BIGSERIAL PRIMARY KEY,

content TEXT NOT NULL,

source VARCHAR(255),

page INTEGER,

embedding vector(1536), -- 임베딩 컬럼

created_at TIMESTAMP DEFAULT NOW()

);

-- HNSW 인덱스 생성 (쿼리 성능 핵심)

CREATE INDEX ON documents

USING hnsw (embedding vector_cosine_ops)

WITH (m = 16, ef_construction = 64);

-- m: 연결 수 (높을수록 정확, 메모리 증가)

-- ef_construction: 빌드 품질 (높을수록 좋음, 빌드 느림)

-- 코사인 유사도 검색

SELECT

id,

content,

source,

1 - (embedding <=> $1) AS similarity

FROM documents

ORDER BY embedding <=> $1 -- <=> 코사인 거리

LIMIT 5;

-- 메타데이터 필터링과 조합

SELECT id, content, similarity

FROM (

SELECT

id,

content,

1 - (embedding <=> $1) AS similarity

FROM documents

WHERE source = 'guide.pdf' -- 일반 PostgreSQL 필터

) sub

WHERE similarity > 0.8 -- 유사도 임계값

ORDER BY similarity DESC

LIMIT 10;

Python에서 사용:

from openai import OpenAI

client_openai = OpenAI()

def semantic_search(query: str, conn, top_k: int = 5) -> list:

"""pgvector를 사용한 시맨틱 검색"""

쿼리 임베딩 생성

query_embedding = client_openai.embeddings.create(

input=query,

model="text-embedding-3-small"

).data[0].embedding

벡터를 pgvector 형식으로 변환

embedding_str = str(query_embedding)

with conn.cursor() as cur:

cur.execute("""

SELECT id, content, source,

1 - (embedding <=> %s::vector) AS similarity

FROM documents

ORDER BY embedding <=> %s::vector

LIMIT %s

""", (embedding_str, embedding_str, top_k))

results = cur.fetchall()

return [

{"id": r[0], "content": r[1], "source": r[2], "similarity": r[3]}

for r in results

]

사용 예시

conn = psycopg2.connect("postgresql://user:pass@localhost/mydb")

results = semantic_search("인공지능 기술 동향", conn)

for r in results:

print(f"[{r['similarity']:.3f}] {r['content'][:80]}")

**장점:**

- 기존 PostgreSQL 인프라 재사용

- ACID 트랜잭션 지원 (벡터와 일반 데이터 원자적 처리)

- 복잡한 SQL 쿼리와 자연스러운 조합

- 운영 비용 절감

**단점:**

- 수천만 건 이상에서 전용 벡터 DB 대비 성능 떨어짐

- 인덱스가 메모리에 상주해야 최적 성능

- 분산 처리 제한

**적합한 상황:** 이미 PostgreSQL 사용 중, 데이터가 RDB와 결합 필요, 비용 절감 우선

결정 매트릭스

| 상황 | 최고 선택 | 이유 |

|------|---------|------|

| 프로토타입/PoC | Chroma | 가장 쉽게 시작 |

| PostgreSQL 팀 | pgvector | 인프라 재활용, 낮은 운영 비용 |

| 빠른 프로덕션 론칭 | Pinecone | 제로 운영, 즉시 스케일링 |

| 자체 인프라 + 대규모 | Weaviate 또는 Qdrant | 오픈소스, 완전한 제어 |

| 하이브리드 검색 필수 | Weaviate | 벡터+BM25 네이티브 지원 |

| 수십억 벡터 이상 | Qdrant 또는 Milvus | 초대규모 최적화 |

| 비용 최소화 | pgvector | 별도 DB 비용 없음 |

성능 비교 (동일 조건 벤치마크)

테스트 조건: 100만 개 1536차원 벡터, cosine similarity, top-5 검색

초당 쿼리 처리량 (QPS):

─────────────────────────────────────────

Pinecone Serverless: ~2,000 QPS (자동 스케일링)

Weaviate (HNSW): ~1,500 QPS (단일 인스턴스)

pgvector (HNSW): ~800 QPS (단일 인스턴스, RAM에 인덱스 적재 시)

Chroma: ~200 QPS (단일 스레드 한계)

지연시간 (p99, 100만 벡터):

─────────────────────────────────────────

Pinecone: ~50ms

Weaviate: ~30ms (로컬)

pgvector: ~20ms (인덱스 완전 메모리 적재 시)

Chroma: ~100ms+

주의: 이 수치는 환경에 따라 크게 달라진다. 실제 데이터로 벤치마크를 직접 실행할 것을 강력히 권장한다.

마이그레이션 전략

벡터 DB를 나중에 교체해야 할 경우를 대비한 추상화 레이어:

from abc import ABC, abstractmethod

class VectorStoreBase(ABC):

"""벡터 DB 추상화 레이어"""

@abstractmethod

def upsert(self, ids: list, embeddings: list, metadatas: list) -> None:

pass

@abstractmethod

def search(self, query_embedding: list, top_k: int = 5) -> list:

pass

@abstractmethod

def delete(self, ids: list) -> None:

pass

class ChromaVectorStore(VectorStoreBase):

def __init__(self, collection_name: str):

self.client = chromadb.PersistentClient(path="./chroma_db")

self.collection = self.client.get_or_create_collection(collection_name)

def upsert(self, ids, embeddings, metadatas):

self.collection.upsert(ids=ids, embeddings=embeddings, metadatas=metadatas)

def search(self, query_embedding, top_k=5):

results = self.collection.query(query_embeddings=[query_embedding], n_results=top_k)

return [{"id": id_, "score": 1-dist}

for id_, dist in zip(results["ids"][0], results["distances"][0])]

def delete(self, ids):

self.collection.delete(ids=ids)

class PineconeVectorStore(VectorStoreBase):

def __init__(self, index_name: str):

from pinecone import Pinecone

pc = Pinecone(api_key="your-key")

self.index = pc.Index(index_name)

def upsert(self, ids, embeddings, metadatas):

vectors = [{"id": id_, "values": emb, "metadata": meta}

for id_, emb, meta in zip(ids, embeddings, metadatas)]

self.index.upsert(vectors=vectors)

def search(self, query_embedding, top_k=5):

results = self.index.query(vector=query_embedding, top_k=top_k)

return [{"id": m.id, "score": m.score} for m in results.matches]

def delete(self, ids):

self.index.delete(ids=ids)

환경에 따라 구현체 교체 가능

def get_vector_store(provider: str) -> VectorStoreBase:

if provider == "chroma":

return ChromaVectorStore("my_collection")

elif provider == "pinecone":

return PineconeVectorStore("my-index")

else:

raise ValueError(f"Unknown provider: {provider}")

이 패턴을 사용하면 초반에 Chroma로 시작해 나중에 Pinecone이나 Weaviate로 마이그레이션할 때 비즈니스 로직 변경이 최소화된다.

결론

벡터 DB 선택에 정답은 없다. 상황에 따라 다르다.

**빠르게 시작해야 한다면:** Chroma로 프로토타입 → 요구사항 명확해지면 적합한 프로덕션 DB로 이전.

**이미 PostgreSQL이 있다면:** pgvector를 먼저 시도해라. 수백만 건 이하에서는 충분하고, 운영 복잡도가 가장 낮다.

**팀에 운영 리소스가 없다면:** Pinecone Serverless로 시작해라. 비용이 나중에 문제가 되면 그때 이전을 검토한다.

**대규모 자체 인프라가 있다면:** Weaviate나 Qdrant를 검토해라. 하이브리드 검색이 필요하다면 Weaviate가 단연 최고다.

현재 단락 (1/324)

RAG 시스템을 구축하다 보면 필연적으로 벡터 데이터베이스를 선택해야 하는 순간이 온다. Pinecone, Weaviate, Chroma, pgvector, Qdrant... 선택...

작성 글자: 0원문 글자: 8,818작성 단락: 0/324