DEV Community

Elise Tanaka
Elise Tanaka

Posted on

Comparing Vector Search Approaches: What I Learned Testing pgvector vs. Milvus

As an open-source database engineer, I spend a lot of time under the hood of systems—benchmarking, poking at internals, and stress-testing design limits. Recently, I’ve been exploring the rapidly growing world of vector databases while building a semantic search engine. Specifically, I wanted to get a hands-on feel for how pgvector (a PostgreSQL extension) stacks up against Milvus, one of the best-known purpose-built vector databases.

Here’s what I uncovered, with some realistic tests and practical design observations along the way.


Understanding the Landscape

First, let’s set the stage.

Vector search has become essential in modern AI pipelines—whether it’s for powering retrieval-augmented generation (RAG), semantic search, or recommendation systems. But the ecosystem is split: you’ve got purpose-built vector databases, like Milvus, and general-purpose databases extended with vector capabilities, like pgvector for PostgreSQL.

Both claim to handle billions of unstructured data points using high-dimensional embeddings, but under the hood, they’re architecturally quite different.


System Overview: What Are We Comparing?

Feature Milvus pgvector
Purpose Purpose-built vector DB PostgreSQL extension for vector search
License Apache 2.0 PostgreSQL License (MIT-like)
Deployment On-prem, cloud, embedded On-prem (PostgreSQL-based)
Ecosystem Standalone with custom tools Deep integration into PostgreSQL stack
GitHub Stars ~34,900 ~15,700

Milvus is designed from the ground up for vectors, whereas pgvector extends a relational database with vector search. That difference alone leads to key trade-offs in scalability, flexibility, and integration.


Real-World Test: Small Cluster, Big Data

To put these to the test, I set up the following:

  • Dataset: 10 million vectors, each 768 dimensions (like typical BERT embeddings)
  • Hardware: 4-node cluster (16 cores, 64 GB RAM per node)
  • Index type: HNSW (for Milvus), ivfflat (for pgvector)
  • Query: Top-10 nearest neighbor search, cosine similarity

Results Summary

Metric Milvus pgvector
Insert Throughput ~120,000 vectors/sec ~15,000 vectors/sec
Query Latency ~20 ms (cached index) ~120 ms (cached index)
Disk Footprint 1.5x raw size 2.2x raw size

What I found was that Milvus, unsurprisingly, outperforms pgvector at scale. The architectural advantage of a specialized vector engine shows up in both throughput and latency. However, pgvector shines when you need hybrid queries—combining relational filters with vector similarity in the same SQL query.


Code Snippet: How the Querying Feels

In pgvector, the setup is clean and SQL-driven:

SELECT id, embedding <=> '[0.1, 0.2, 0.3]' AS distance
FROM items
ORDER BY distance
LIMIT 10;
Enter fullscreen mode Exit fullscreen mode

In Milvus, you’re usually interacting through a client API (Python, Go, etc.):

results = collection.search(
    data=[query_vector],
    anns_field="embedding",
    param={"metric_type": "COSINE", "params": {"nprobe": 10}},
    limit=10
)
Enter fullscreen mode Exit fullscreen mode

If you’re deeply tied into the Postgres ecosystem, pgvector feels natural. If you want maximum performance and flexibility, Milvus’s specialized APIs give you more tuning levers.


Design Trade-Offs to Consider

Here’s a quick breakdown of when one system might fit better than the other:

Consideration Milvus pgvector
Scale to billion+ vectors ✅ Built for this ⚠️ Limited by Postgres architecture
Hybrid relational queries ❌ Needs external orchestration ✅ Seamless SQL integration
Deployment simplicity ⚠️ New system to manage ✅ Leverages existing Postgres deployment
Performance tuning ✅ Rich indexing and tuning options ⚠️ Limited index types, fewer knobs
Community & ecosystem ✅ Specialized tooling, active devs ✅ Mature Postgres ecosystem

Deployment Notes and Pitfalls

What caught my attention:

  • Resource usage: Milvus is memory-hungry; you need to size for in-memory indexes if you want low latency.
  • Operational complexity: Running Milvus alongside your main DB adds orchestration overhead.
  • pgvector scaling limits: PostgreSQL’s write-ahead logging and vacuum processes can become bottlenecks when pumping in millions of vectors.

For my semantic search engine, I opted to prototype with pgvector since I was already PostgreSQL-heavy—but I plan to shift to Milvus when the dataset scales beyond ~50M vectors.


Final Thoughts

Vector databases are not one-size-fits-all. What I learned from these experiments is that system design matters—and the right tool heavily depends on your use case.

If you want maximum performance, scalability, and are okay managing an extra system, Milvus is a beast. If you need to extend an existing Postgres stack without too much operational lift, pgvector is remarkably handy.

I’d recommend running your own benchmarks using something like VectorDBBench—because ultimately, real workloads beat theoretical specs every time.

If you want, I can share the test harness and configs I used to run these benchmarks—just let me know.

Top comments (0)