AI Models

Comparing vector databases by access pattern, not benchmarks

A framework for choosing between pgvector, Qdrant, Pinecone, and Weaviate based on query type, filter support, indexing latency, and hybrid search capabilities.

Mohammed Saqib8 min read
System with various wires managing access to centralized resource of server in data center
Photo by Brett Sayles on Pexels · Pexels License

When you evaluate vector databases, the first thing you reach for is a benchmark. A GitHub repo with recall‑vs‑latency curves, a blog post claiming “10x faster than Pinecone”, or a vendor’s own throughput numbers. Those numbers are almost useless for your workload. Your queries involve filters, partial updates, mixed read/write patterns, and data arrival rates that no canned benchmark captures. The right way to choose is to map your access patterns—query type, filter selectivity, ingestion frequency, latency budget—to each system’s architectural trade‑offs.

Why access patterns beat benchmarks

Benchmarks measure throughput under synthetic workloads on identical hardware. In production, your hardware is different, your data distribution is different, and your queries are never uniform. A benchmark that reports 95th‑percentile latency for pure ANN search means nothing if your queries are 80% filtered by a user ID that matches only 0.1% of vectors. The real performance depends on how each system handles that filter: pre‑filter, post‑filter, or hybrid traversal.

Access patterns include:

  • Query type: exact nearest neighbor (brute force) vs approximate (ANN). Do you need 100% recall, or is 99% acceptable?
  • Filter selectivity: how many vectors survive the filter? High selectivity (few matches) punishes post‑filter systems.
  • Data arrival rate: are you ingesting 10 vectors/second or 10,000? Batch loads vs streaming updates affect index maintenance.
  • Latency budget: 5 ms p99 vs 50 ms changes whether you can afford HNSW’s memory or need on‑disk indexing.

Ignore throughput numbers from someone else’s hardware. Focus on the mechanics that determine your own tail latencies.

Query type: exact vs approximate nearest neighbor

Every vector database supports approximate nearest neighbor (ANN) search. The difference is whether they also support exact search and how they expose index parameters.

pgvector offers both. For exact search you simply omit an index, which does a brute‑force scan. That works up to about 100k vectors; beyond that, the O(n) cost becomes untenable. For ANN you choose between IVFFlat and HNSW. IVFFlat builds quickly (minutes for millions of vectors) but queries can be 10x slower than HNSW at high recall. HNSW builds slower but queries in microseconds. You control this via lists and probes for IVFFlat, or m and ef_construction for HNSW.

-- pgvector: create HNSW index with default parameters
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops)
  WITH (m = 16, ef_construction = 200);

Qdrant and Weaviate use HNSW by default. You configure m and ef_construct at collection creation time. Larger values improve recall but increase memory and build time. Both systems also support exact search via a separate query mode (e.g., Qdrant’s exact: true), though that is rarely used in production.

Pinecone abstracts away all index tuning. You pick a pod size and it handles graph maintenance internally. That reduces operational overhead but removes knobs. If your workload has tight latency requirements that benefit from tuning ef per query, Pinecone gives you no control. The trade‑off is simplicity versus flexibility.

Filtering: pre‑filter, post‑filter, and hybrid

Filtering is the biggest differentiator among vector databases. A query like “find the top‑10 most similar vectors where user_id = 42” can be executed in three ways:

  • Post‑filter: run ANN, then discard results that don’t match the filter. If the filter is highly selective, you may waste most of the search.
  • Pre‑filter: apply the filter first, then run ANN on the filtered set. If the filter is selective, this is fast; if not, you still have a large set to search.
  • Hybrid (filtered ANN): the filter is applied during the HNSW graph traversal, pruning nodes that don’t satisfy the predicate.

pgvector applies filters after the index scan unless you use a custom index with payload filtering. That means a filtered query with high selectivity can be very slow—you search the entire index and then throw away 99.9% of results. A workaround is to create multiple indexes per filter value, but that doesn’t scale.

Qdrant has a payload index that filters during the HNSW traversal. You define a payload schema, and the engine uses it to skip irrelevant nodes. This makes high‑selectivity queries almost as fast as unfiltered ANN. The cost is extra memory for the payload index and slower writes.

# Qdrant: create collection with payload index on user_id
from qdrant_client import QdrantClient, models
 
client = QdrantClient()
client.create_collection(
    collection_name="items",
    vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE),
    optimizers_config=models.OptimizersConfigDiff(payload_indexing=True),
)
client.create_payload_index(
    collection_name="items",
    field_name="user_id",
    field_type=models.PayloadFieldType.INTEGER,
)

Weaviate uses an inverted index for filtering combined with HNSW. Performance degrades when the filter matches few results unless you tune the maxIoBudget parameter. Weaviate also supports a hybrid search that combines dense vector similarity with BM25 scoring on text fields—useful for semantic search over documents.

Latency profiles: indexing vs query time

Indexing latency and query latency are a trade‑off. The faster you build an index, the slower it queries, and vice versa.

pgvector’s IVFFlat builds quickly—a few minutes for a million vectors. Queries, however, can be 10x slower than HNSW at equivalent recall. HNSW builds 5–10x slower but provides microsecond queries. If your workload is write‑heavy with occasional reads, IVFFlat may be a better fit. If reads dominate, HNSW is worth the build time.

Qdrant and Weaviate both rely on HNSW. Indexing time scales with m and ef_construct. A typical configuration (m=16, ef_construct=200) builds an index on a million 768‑dim vectors in about 10 minutes on a modern machine. Queries are sub‑millisecond. The memory footprint is roughly 1.5–2x the raw vector size.

Pinecone hides index creation time, but you pay for idle pods. Cold starts can add seconds to the first query after scaling down—the pod needs to load the index from disk. There is no way to avoid this cost; you must keep pods warm or accept latency spikes.

Data types and distance functions

Not all vector databases support the same data types. If you work with binary vectors, sparse vectors, or half‑precision floats, check compatibility.

pgvector supports L2, inner product, and cosine distance for float vectors. It also offers halfvec for memory savings, though with lower precision. There is no native support for sparse vectors or binary vectors.

Qdrant and Weaviate support dot product, cosine, and Euclidean distances. Both also support sparse vectors for BM25‑style hybrid search. Qdrant additionally offers multi‑vector (multiple vectors per point) and named vectors. Weaviate has a built‑in module for text2vec that generates embeddings on the fly.

Pinecone supports dense vectors only (cosine, dot product, Euclidean). No native sparse or binary vectors. This can be a gotcha for code search or hash‑based methods. If you need sparse vectors, you must either use a different database or simulate them with separate indices.

Failure modes: memory bloat, cold starts, and reindexing

HNSW graphs grow linearly with the number of vectors. A 10M vector index with 768‑dimensional floats consumes about 10 GB of RAM for the graph structure alone, plus the raw vectors. pgvector can spill to disk at a severe latency penalty—queries become 100x slower. Qdrant and Weaviate keep everything in memory; if you exceed available RAM, the system starts swapping and performance collapses.

Cold starts occur when a fresh index has no graph built. Queries during build are slow or fall back to brute force. Pinecone mitigates this with background indexing—your first query after creating a collection may be slow, but subsequent ones are fast. Qdrant and Weaviate require explicit warm‑up: you must run a few queries or set optimizers_config to build the index before handling traffic.

Reindexing after bulk updates forces a pause or a shadow index. pgvector's CREATE INDEX blocks writes on the table. You can work around this by building the index concurrently (using CONCURRENTLY), but that takes longer and uses more resources. Qdrant allows simultaneous reads but not writes during a full reindex. Weaviate has a similar limitation. Pinecone handles reindexing transparently, but you pay for the underlying pod.

Decision matrix for choosing a vector database

Criterion pgvector Qdrant Weaviate Pinecone
Best for Postgres users, < 1M vectors, simple filters Filtered search, hybrid search, large scale Semantic search, hybrid with text, multi‑tenant Zero ops, mid‑scale, no custom tuning
ANN index IVFFlat or HNSW HNSW HNSW Proprietary (HNSW‑like)
Filter support Post‑filter (slow on high selectivity) Payload index (fast on high selectivity) Inverted index + HNSW (fast on high selectivity) Post‑filter only
Sparse vectors No Yes Yes No
Horizontal scaling Limited (read replicas, no sharding) Sharding + replication Replication + sharding Automatic sharding
Cold start Fast (no graph) Requires warm‑up Requires warm‑up Background indexing
Write blocking during reindex Yes (unless CONCURRENTLY) Reads OK, writes blocked Reads OK, writes blocked No blocking

Key takeaways

  • Match the filtering mechanism to your query selectivity: high selectivity needs a payload index (Qdrant, Weaviate) rather than post‑filter (pgvector, Pinecone).
  • If you already use PostgreSQL and have under 1M vectors with simple filters, start with pgvector—it integrates naturally and avoids an extra service.
  • For hybrid search (dense + sparse) or high‑throughput filtered search, Qdrant or Weaviate offer better performance and richer payload filtering.
  • Pinecone is a good zero‑ops choice for mid‑scale workloads where you accept vendor lock‑in and per‑pod pricing, but it lacks sparse vectors and filter acceleration.
  • Memory budget is the hard constraint: HNSW graphs can exceed your RAM allocation faster than you expect. Plan for 2x the raw vector size.

When you design your retrieval pipeline, remember that embedding quality and chunking strategy matter as much as the database engine. If you’re building RAG over messy documents, see RAG Chunking Strategies for Messy Real-World Documents. And if you’re measuring cost, Token counting is wrong: measure actual LLM cost explains why.

Frequently asked questions

When should I use pgvector instead of a dedicated vector database?
pgvector is ideal when your data already lives in PostgreSQL and you need simple nearest neighbor search with standard SQL joins. Dedicated databases like Qdrant or Pinecone pull ahead when you need high-throughput filtered search, hybrid (dense + sparse) retrieval, or features like quantization and multi-tenancy that pgvector doesn't provide natively.
What's the difference between pre-filtering and post-filtering for vector databases?
Pre-filtering applies a scalar filter before the approximate nearest neighbor scan, which can miss relevant vectors if the filter is selective and the vector index isn't covering. Post-filtering retrieves many neighbors and then filters, which works but wastes IO. The best approach depends on the database – Qdrant uses a quantized filter index, Pinecone uses a metadata filter combined with the index, and pgvector relies on sequential scan when filtering is too restrictive.
How do I handle cold start latency with vector databases?
Cold indexes (empty or just populated) have no memory of the data distribution, so initial queries may be slow until the HNSW graph warms up. Reindexing after bulk inserts can also spike memory and latency. If you need consistent query performance from the start, consider databases like Pinecone that manage background indexing, or pre‐warm indexes in Qdrant with a dummy query.
#vector-databases#embeddings#search#infrastructure
Share

Keep reading