Skip to main content
AI/ML

Vector Databases Compared: Running the Same RAG Pipeline on pgvector, Qdrant, Pinecone, and Weaviate

9 min read
LD
Lucio Durán
Engineering Manager & AI Solutions Architect
Also available in: Español, Italiano

The Test Setup

Dataset: 2.3M document chunks from a customer support knowledge base. Average chunk size: 512 tokens. Embedded with text-embedding-3-small (1536 dimensions).

Queries: 10,000 real user queries collected from production logs (anonymized). Mix of short ("reset password"), medium ("how to configure SSO with Azure AD"), and long queries ("our team is migrating from on-premise to cloud and we need to understand the data residency implications for GDPR compliance").

Hardware:

  • pgvector: RDS db.r7g.xlarge (4 vCPU, 32GB RAM), PostgreSQL 16 with pgvector 0.8
  • Qdrant: 3-node cluster on c7g.xlarge (4 vCPU, 8GB RAM each), Qdrant 1.13
  • Pinecone: Serverless (Standard), us-east-1
  • Weaviate: 3-node cluster on c7g.xlarge, Weaviate 1.28

Search: Top-10 nearest neighbors, cosine similarity, with metadata filter (category = specific value, reducing candidates by ~80%).

Raw Numbers: Latency and Throughput

Query Latency (10K queries, ms)

Database p50 p95 p99 p99.9
pgvector (HNSW) 8.2 14.1 22.3 41.7
pgvector (IVF) 12.4 24.8 38.1 67.2
Qdrant 3.1 5.8 8.4 14.2
Pinecone Serverless 18.4 32.1 48.7 142.3
Weaviate 5.7 11.2 18.9 33.4

Qdrant wins on raw latency, and it's not close. Their Rust-based engine with memory-mapped storage is genuinely fast. But look at Pinecone's p99.9 — that 142ms tail is the serverless cold start biting you. For interactive applications, that tail is a problem.

pgvector with HNSW is surprisingly competitive. At 8.2ms p50, that's fast enough for any RAG application. The gap widens at the tail, but for most use cases, this is more than adequate.

Throughput (queries/second, 100 concurrent connections)

Database QPS (no filter) QPS (with filter) Delta
pgvector (HNSW) 2,840 2,120 -25.4%
Qdrant 8,420 7,180 -14.7%
Pinecone 1,200 980 -18.3%
Weaviate 4,100 3,250 -20.7%

The filtering performance difference is revealing. pgvector loses 25% throughput with filters because it applies them post-HNSW search (a known limitation). Qdrant integrates filtering into the search algorithm, so the penalty is smaller. Weaviate falls somewhere in between.

Pinecone's throughput ceiling is notably lower than what might be expected for a managed service. The serverless architecture prioritizes per-query cost optimization over raw throughput.

HNSW vs IVF: When Each Wins

pgvector 0.8 supports both HNSW and IVF-Flat indexes. The choice matters more than most people realize.

HNSW (Hierarchical Navigable Small World)

CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 256);

-- At query time
SET hnsw.ef_search = 100;

Pros: Fast queries, high recall, no training step Cons: High memory usage (~1.5x the vector data), slow index builds

HNSW build time for 2.3M vectors at 1536 dimensions: 47 minutes on our RDS instance. Memory usage: 14.2GB for the index alone.

IVF-Flat (Inverted File with Flat quantization)

CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 1500);

-- At query time
SET ivfflat.probes = 40;

Pros: Lower memory usage (~0.3x), faster index builds Cons: Requires training (the lists parameter needs tuning), lower recall at the same latency

IVF build time: 12 minutes. Memory: 4.1GB. But recall at the same latency was 91.2% vs HNSW's 97.8%.

Recommendation

Use HNSW unless memory is the binding constraint. The recall difference (97.8% vs 91.2%) means that for every 100 queries, IVF misses ~7 relevant results that HNSW finds. In a RAG pipeline, those missed chunks directly impact answer quality.

Quantization: The Memory vs Quality Tradeoff

At 2.3M vectors with 1536 dimensions (float32), the raw vector data is about 13.4GB. Quantization reduces this dramatically:

pgvector: halfvec (float16)

-- pgvector 0.8 supports halfvec natively
ALTER TABLE documents
 ALTER COLUMN embedding TYPE halfvec(1536);

-- Index works the same
CREATE INDEX ON documents
USING hnsw (embedding halfvec_cosine_ops);

Memory reduction: 50%. Recall impact: -0.8% (negligible). This is a no-brainer for pgvector users. Half-precision floats lose almost nothing for similarity search.

Qdrant: Binary Quantization with Rescoring

{
 "collection_name": "documents",
 "vectors": {
 "size": 1536,
 "distance": "Cosine",
 "quantization_config": {
 "binary": {
 "always_ram": true
 }
 }
 },
 "quantization_config": {
 "binary": {
 "always_ram": true
 }
 }
}

Binary quantization reduces each float32 to a single bit. 32x memory reduction. But raw recall drops to ~85%. The trick is rescoring: Qdrant first searches the binary index to get a candidate set (say, top-100), then rescores those candidates against the full-precision vectors. Final recall: 94.7% at a fraction of the memory.

In benchmark testing:

Qdrant Mode Memory p50 Latency Recall@10
Full precision 14.8GB 3.1ms 98.2%
Binary (no rescore) 0.46GB 1.2ms 84.9%
Binary + rescore 100 0.46GB + 14.8GB disk 4.8ms 94.7%
Scalar (int8) 3.7GB 2.8ms 96.1%

The scalar quantization (int8) is the sweet spot for most workloads: 75% memory reduction with only 2.1% recall loss.

Pinecone: Automatic Quantization

Pinecone serverless applies quantization automatically and opaquely. You don't control it. In our tests, their recall was 93.8% — suggesting aggressive quantization behind the scenes. For some applications this is fine; for others, the lack of control is frustrating.

The Hybrid Search Question

Real RAG pipelines don't just do vector search. You need keyword matching, metadata filtering, and often both combined. Here's where the architectures diverge sharply.

pgvector: The Unfair Advantage

-- Hybrid search: vector similarity + full-text search + metadata filter
WITH vector_results AS (
 SELECT id, content,
 1 - (embedding <=> $1::vector) AS vector_score
 FROM documents
 WHERE category = $2
 ORDER BY embedding <=> $1::vector
 LIMIT 20
),
text_results AS (
 SELECT id, content,
 ts_rank(search_vector, plainto_tsquery($3)) AS text_score
 FROM documents
 WHERE category = $2
 AND search_vector @@ plainto_tsquery($3)
 LIMIT 20
)
SELECT COALESCE(v.id, t.id) AS id,
 COALESCE(v.content, t.content) AS content,
 COALESCE(v.vector_score, 0) * 0.7 +
 COALESCE(t.text_score, 0) * 0.3 AS combined_score
FROM vector_results v
FULL OUTER JOIN text_results t ON v.id = t.id
ORDER BY combined_score DESC
LIMIT 10;

This is pgvector's killer feature: hybrid search in a single query, with the full power of PostgreSQL's query planner. No external orchestration, no separate keyword index, no result fusion in application code.

Qdrant: Payload Filtering

from qdrant_client import QdrantClient, models

results = client.search(
 collection_name="documents",
 query_vector=query_embedding,
 query_filter=models.Filter(
 must=[
 models.FieldCondition(
 key="category",
 match=models.MatchValue(value="billing")
 )
 ]
 ),
 limit=10,
 search_params=models.SearchParams(
 hnsw_ef=100,
 exact=False
 )
)

Qdrant handles metadata filtering well (integrated into the HNSW search), but keyword search requires a separate full-text index and manual fusion. For simple filter + vector search, it's excellent. For true hybrid search, you're building the fusion logic yourself.

Weaviate: Built-in Hybrid

{
 Get {
 Document(
 hybrid: {
 query: "SSO Azure AD configuration"
 alpha: 0.7
 fusionType: relativeScoreFusion
 }
 where: {
 path: ["category"]
 operator: Equal
 valueText: "authentication"
 }
 limit: 10
 ) {
 content
 _additional {
 score
 }
 }
 }
}

Weaviate has the best hybrid search story among the dedicated vector databases. The alpha parameter controls the vector vs keyword weight, and relativeScoreFusion handles the score normalization. It's not quite as flexible as raw SQL, but it's production-ready out of the box.

Cost Analysis (The Part That Decides)

For 2.3M vectors at 1536 dimensions, running 24/7:

Database Monthly Cost Notes
pgvector (RDS r7g.xlarge) $412 Includes compute + storage
pgvector (Neon Pro) $69-190 Scales to zero, pay per query
pgvector (Supabase Pro) $75-200 Includes other Postgres features
Qdrant Cloud (3-node) $720 Dedicated cluster
Qdrant (self-hosted EC2) $390 3x c7g.xlarge
Pinecone Serverless $280-650 Depends on query volume
Weaviate Cloud $580 Managed 3-node

pgvector on Neon or Supabase is absurdly cheap for small-to-medium workloads. And because it's just Postgres, you're not paying for a separate service — your vectors live next to your relational data.

For high-throughput workloads (>1000 QPS sustained), Qdrant self-hosted on ARM instances is the price-performance winner.

Pinecone's serverless pricing is attractive at low volumes but scales unpredictably. In one case, query patterns changed and the bill jumped 2.3x.

Practical Recommendations

For most startups and MVPs: pgvector on Supabase or Neon. You get a vector database and a relational database in one. Hybrid search works out of the box. The latency is good enough. You can always migrate later if you outgrow it, and in practice, most products never will.

For high-throughput, latency-sensitive production: Qdrant. The Rust engine is genuinely faster, the quantization options give you fine-grained control over the memory/recall tradeoff, and the filtering is well-integrated. Self-host on Graviton instances for the best price-performance.

For teams that want managed everything and don't mind the cost: Pinecone. It works, it's simple, and you don't have to think about infrastructure. Just know that you're paying a premium for that simplicity, and the serverless cold starts will bite you.

For hybrid search-heavy applications: Weaviate if you want a dedicated vector DB, pgvector if you want the flexibility of SQL. Weaviate's GraphQL API for hybrid search is well-designed and saves development time.

The Uncomfortable Truth

Here's what nobody in the vector database space wants to admit: for 90% of RAG applications, pgvector is sufficient. The dedicated vector databases are faster, but "faster" means 3ms vs 8ms — both are invisible to the end user who's waiting 800ms for the LLM to generate a response.

The real differentiator is at scale (>10M vectors), at extreme throughput (>5000 QPS), or when you need sub-5ms p99 latency for real-time applications. If that's you, Qdrant or Weaviate are worth the operational complexity. If it's not — and be honest about whether it is — just use pgvector and spend your engineering time on what actually moves the needle: better chunking strategies, better prompts, and better evaluation.

The boring choice is often the right one.

vector-databasespgvectorqdrantpineconeweaviateragembeddingshnswai

Tools mentioned in this article

SupabaseTry Supabase
NeonTry Neon
Disclosure: Some links in this article are affiliate links. If you sign up through them, I may earn a commission at no extra cost to you. I only recommend tools I personally use and trust.
Seguime