A production benchmark compares pgvector with dedicated vector databases.
pgvector with pgvectorscale outperformed Qdrant in throughput but lost on tail latency; local tests teach benchmarking, not production fit.
Key Points Summary
- A 50 million-vector production benchmark showed Postgres with pgvector and pgvectorscale achieving 11.4 times higher query throughput than Qdrant at 99% recall.
- Qdrant provided lower tail latency, cutting p99 by 48%, and built its index about 3.4 times faster than the Postgres setup.
- The benchmark compared pgvector plus pgvectorscale, not vanilla pgvector alone, which is important when interpreting the results.
- A 100,000-vector local benchmark is useful for learning the setup workflow, but too small to support real production decisions.
- pgvector simplifies architecture by keeping vector search inside Postgres, while dedicated vector databases add operational complexity but may better optimize latency and indexing.
Meta description: A benchmark comparison of pgvector and Qdrant covers local tests, Tiger Data production results, throughput, latency, and when each vector search setup fits.
Tags: pgvector, Qdrant, vector databases, Postgres, benchmarking
Featured image: abstract illustration of two database engines balancing latency and throughput, friendly style, no real people, logos, or text.
For teams deciding whether pgvector and Qdrant benchmarks justify a migration, the measured answer is split: a 50 million-vector Tiger Data test showed Postgres with pgvector and pgvectorscale delivering 11.4 times more queries per second than Qdrant at 99% recall, while Qdrant cut p99 latency by 48%. A common scenario is a team adding pgvector to Postgres on a Tuesday afternoon, then six months later receiving a vendor pitch that a dedicated vector database is required, without numbers in either direction.
The production numbers that matter most
Tiger Data’s published benchmark is the most detailed, methodologically transparent public comparison against pgvector available, according to the source. It tested 50 million real Cohere embeddings at 768 dimensions on matched AWS r6id.4xlarge hardware, each machine configured with 16 virtual CPUs and 128GB RAM, using a modified fork of the industry-standard ANN-Benchmarks tool.
One nuance is essential: the test used Postgres with pgvector plus pgvectorscale, Timescale’s own additional extension that adds a different index type called StreamingDiskANN, not vanilla pgvector alone. Many secondary summaries blur that point, so the figures describe the combined setup.
At 99% recall, the Postgres configuration achieved 471.57 queries per second, versus 41.47 queries per second for Qdrant, a 11.4-fold throughput advantage. Qdrant’s counterpoint was tail latency: its p99 was 38.71ms compared with 74.60ms, a 48% improvement, and it built its index roughly 3.4 times faster. Both systems kept every measured percentile under 100ms at 99% recall on the 50-million-vector dataset, directly undercutting the assumption that a general-purpose database cannot keep up at real scale.
How to run a local pgvector and Qdrant benchmark
The source provides a laptop-sized benchmark with 100,000 vectors. It is useful for learning the workflow, not for production selection.
Prerequisites: Docker, Docker Compose, Python 3.10 or later, about 8GB of free RAM, and basic comfort reading structured query language (SQL) and Python.
- Start pgvector with a Docker Compose file using pgvector/pgvector:pg17, the official Docker image that bundles the extension with Postgres 17. After docker compose up -d, connect and run CREATE EXTENSION IF NOT EXISTS vector, the one-time step that registers the vector type and index methods in that database.
- Start Qdrant with its single Docker command. Then create a collection with VectorParams(size=1536, distance=Distance.COSINE), matching the dimensionality and cosine distance used in the pgvector table. A fair comparison needs both systems measuring the same thing.
- Generate synthetic vectors and load 100,000 rows into each system. For pgvector, use pgvector-python’s adapter with psycopg2; register_vector(conn) teaches psycopg2 how to convert NumPy arrays so execute_values can insert raw arrays without manual string formatting. For Qdrant, use upsert in batches of 1,000 vectors, because batched inserts are faster than one giant request or single-vector writes.
- Create comparable Hierarchical Navigable Small World (HNSW) indexes. In pgvector, follow its own indexing documentation. In Qdrant, apply the same underlying algorithm and settings: m=16 and ef_construction=64, pgvector’s defaults. If the index parameters differ, the benchmark results are not comparable.
- Query with 200 fresh held-out vectors, not vectors already loaded. Querying a vector that is already in the index can trivially return itself at zero distance and distort the result. Set SET hnsw.ef_search = 64 for reproducible pgvector behavior; higher values trade speed for better recall. Use pgvector’s cosine distance operator embedding <=> %s and Qdrant’s client.query_points(), the current recommended search method replacing older search() calls.
- Report median p50, 95th percentile p95, and 99th percentile p99 latency plus queries per second for both systems, using the same summarize logic so the outputs are directly comparable line for line.
On a typical laptop, both systems often report latencies in the low single-digit to tens of milliseconds range. The exact numbers depend heavily on CPU, available RAM, and whatever else is running. That variability is the honest lesson: 100,000 vectors is a fine way to confirm setup mechanics, but it is too small a scale to draw a real production conclusion.
Architecture and workload fit
pgvector is an open-source Postgres extension, currently version 0.8.6 and supporting Postgres 13 and later, according to its official GitHub repository. It adds a native vector column type to Postgres, along with exact and approximate nearest-neighbor search, directly inside the database. A vector embedding can live in the same table as the record it describes, queried with the same SQL already known. There is no separate service to stand up, no second system to keep in sync, and no network hop between relational data and vector data. It supports single-precision, half-precision, binary, and sparse vector types, plus five distance functions: L2, inner product, cosine, L1, and Hamming.
A dedicated vector database is a separate, purpose-built service, run as its own process with its own storage engine, designed around vector search rather than having it added onto a general-purpose database. That is a different architectural choice: it means another system to deploy, monitor, back up, and keep synchronized with the source of truth. The source frames this category around five most commonly reached-for options, and its detailed comparison uses Qdrant because that system is the subject of the most transparent public benchmark against pgvector available. It also names Milvus and Pinecone as other choices with specific strengths.
The decision line is concrete. Scale under roughly 5 to 10 million vectors is comfortably within pgvector’s range on reasonable hardware. A genuine need for transactional consistency between relational data and embeddings, such as updating a document and its vector in the same atomic transaction, is a structural advantage pgvector has that a separate database cannot offer. An existing Postgres investment, and a team that already knows how to operate, monitor, and back it up, means adding vector search costs an extension and an index, not a new system. Moderate query concurrency, rather than thousands of simultaneous queries per second, keeps the workload within what a well-tuned Postgres instance handles comfortably.
On the other side, genuinely massive scale, hundreds of millions to billions of vectors, is where purpose-built distributed architectures can earn their operational cost. A hard tail-latency SLA under heavy concurrent filtered search, the kind of requirement where a p99 above 25 to 40 milliseconds is a real problem, favors Qdrant’s demonstrated tail-latency advantage. GPU-accelerated indexing needs point toward Milvus, described as the option built around that from the ground up. A preference for zero-operations managed infrastructure, with no database expertise on the team and no appetite for running or tuning anything, is exactly what a fully managed service like Pinecone exists to remove from your plate.
Common mistakes: who should use it and who should skip it
The most common mistake is treating a laptop benchmark as proof. Another is comparing systems with different index settings, such as changing m or ef_construction on only one side. Teams also weaken tests by querying vectors already loaded into the index, relying on default search settings when reproducibility matters, or ignoring that the production benchmark used pgvectorscale rather than plain pgvector. Finally, choosing by slogan rather than measured workload needs leaves teams overpaying for complexity or underprovisioning for scale.
Use pgvector when the dataset is modest, transactional consistency matters, Postgres is already well operated, and the workload is not thousands of simultaneous queries per second. Skip it when the dataset reaches hundreds of millions to billions of vectors, when a strict tail-latency SLA is non-negotiable, when GPU-accelerated indexing is required, or when the team wants fully managed infrastructure with no database tuning.
Use Qdrant when its tail-latency advantage matters under heavy concurrent filtered search, especially when p99 above 25 to 40 milliseconds is unacceptable. Skip it when the workload is comfortably within 5 to 10 million vectors and the team would rather avoid another system to deploy, monitor, back up, and synchronize.
The benchmark data does not support either clean story: pgvector is not always fine, and dedicated databases do not always win. It shows two systems with genuinely different tradeoffs measured under matched, transparent conditions. One wins decisively on throughput in the tested Postgres plus pgvectorscale setup, the other wins decisively on tail latency, and both comfortably clear the bar most real applications actually need. The answer is whichever side of that tradeoff the actual workload sits on, not whichever system a vendor pitches first.

Comments (0)