pgvector offers tight Postgres integration but lacks distributed scaling; Pinecone, Qdrant, and Milvus provide managed or self‑hosted clusters with higher throughput and built‑in metadata filtering.
Decision checklist
1. Deployment model – pgvector = on‑prem Postgres, Pinecone = SaaS, Qdrant = self‑hosted or Docker, Milvus = self‑hosted (K8s) or Milvus Cloud.
2. Scalability – pgvector maxes out ~200 M vectors on a single node; Pinecone auto‑shards to billions; Qdrant supports horizontal sharding via qdrant_cluster; Milvus scales with milvusctl and can handle >1 B vectors.
3. Hybrid search – pgvector uses vector <->> embedding with ivfflat or hnsw via pgvector.opclass; Pinecone offers vector + filter natively; Qdrant provides vector + payload filters; Milvus supports vector + scalar with HybridSearch API.
4. Latency @ 10 k queries/sec – typical 1‑2 ms for Pinecone (SLA), 3‑5 ms for Qdrant on 8‑core, 4‑6 ms for Milvus on 4‑node cluster, 8‑12 ms for pgvector on a single SSD node.
5. Cost – pgvector = storage + compute; Pinecone = $0.30 per million vectors + $0.0005 per query; Qdrant = open‑source (infrastructure cost); Milvus = open‑source (infrastructure) but Milvus Cloud starts at $0.25 per million vectors.
Example snippets
-- pgvector table
CREATE TABLE docs (
id uuid PRIMARY KEY,
content text,
embedding vector(1536)
);
CREATE INDEX ON docs USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);# Pinecone upsert
import pinecone
pinecone.init(api_key="YOUR_KEY", environment="us-west1-gcp")
index = pinecone.Index("rag-index")
vectors = [(str(uuid4()), embed.tolist(), {"type": "article"}) for embed in batch]
index.upsert(vectors=vectors, namespace="docs")# Qdrant collection config
name: docs
vectors:
size: 1536
distance: Cosine
payload_schema:
type: keyword
fields:
category: string# Milvus index creation
from pymilvus import Collection, FieldSchema, CollectionSchema, DataType, connections
connections.connect("default", host="milvus-standalone", port="19530")
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536)
]
schema = CollectionSchema(fields, "RAG docs")
coll = Collection("docs", schema)
coll.create_index("embedding", {"index_type": "IVF_FLAT", "metric_type": "IP", "params": {"nlist": 1024}})