Vector search in Postgres, measured.
Install guides, tested SQL and benchmarks we ran ourselves on 500,000 real OpenAI embeddings — so you choose index settings from data, not folklore.
Loading embeddings…
Neighbours are exact top-10 by cosine distance in 1,536 dimensions, computed by pgvector. The 2-D layout (t-SNE) can't preserve every distance, so some true neighbours sit far apart on the map. Colours: 12 k-means clusters.
Your embeddings, in the database you already run#
pgvector is an open-source PostgreSQL extension that stores embeddings as a column type and finds nearest neighbours with SQL. No second database, no sync jobs: vectors live next to the rows they describe, inside the same transactions, backups and permissions.
- Four types:
vector,halfvec,bit,sparsevec - Six distances: L2, cosine, inner product, L1, Hamming, Jaccard
- Two indexes: HNSW and IVFFlat, plus exact search
- Free: PostgreSQL License, on Postgres 13+ and every major cloud
The 60-second version — real output from our server:
demo=# SELECT content, embedding <=> '[1, 1, 0]' AS cosine_distance,
demo-# 1 - (embedding <=> '[1, 1, 0]') AS cosine_similarity
demo-# FROM items ORDER BY embedding <=> '[1, 1, 0]' LIMIT 3;
content | cosine_distance | cosine_similarity
---------+----------------------+---------------------
cat | 0.004129399346548546 | 0.9958706006534515
kitten | 0.010674679844520418 | 0.9893253201554796
truck | 0.7712521293869518 | 0.22874787061304824
(3 rows)CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);What the settings actually do#
We loaded DBpedia articles embedded with OpenAI text-embedding-3-large into PostgreSQL 18.6, held out 1,000 queries, and measured every index setting against exact search. Some results surprised us.
Recall vs latency: HNSW and IVFFlat on 100K embeddings
Each point is one setting of ef_search (HNSW) or probes (IVFFlat). Up and to the left is better.
- HNSW (m 16, ef_construction 64)
- IVFFlat (316 lists)
| Index | Setting | Recall@10 | p50 latency |
|---|---|---|---|
| HNSW | ef_search 10 | 0.815 | 1.4 ms |
| HNSW | ef_search 20 | 0.897 | 1.9 ms |
| HNSW | ef_search 40 | 0.947 | 2.9 ms |
| HNSW | ef_search 64 | 0.970 | 3.9 ms |
| HNSW | ef_search 100 | 0.983 | 5.3 ms |
| HNSW | ef_search 200 | 0.990 | 9.1 ms |
| HNSW | ef_search 400 | 0.995 | 16 ms |
| IVFFlat | probes 1 | 0.550 | 1.4 ms |
| IVFFlat | probes 2 | 0.674 | 1.9 ms |
| IVFFlat | probes 4 | 0.778 | 3.1 ms |
| IVFFlat | probes 8 | 0.857 | 5.5 ms |
| IVFFlat | probes 16 | 0.912 | 9.9 ms |
| IVFFlat | probes 32 | 0.953 | 19 ms |
| IVFFlat | probes 64 | 0.978 | 35 ms |
ALTER TABLE: PostgreSQL launched zero parallel workers for 100K rows of 1,536-dim vectors until we set parallel_workers.Why it happens →probes = 1. Raising probes to 16 gave 91.2%.IVFFlat guide →Every topic, tested end to end#
Each guide starts with the answer, shows real psql output, and backs its advice with numbers.
Install
Docker, Windows, macOS, Linux, cloud. Which channels ship 0.8.7, and the Postgres 18 Docker volume trap.
Install guide →HNSW
m, ef_construction, ef_search and build memory — with an interactive graph you can search.
IVFFlat
How many lists and probes, measured at 100K and 500K rows, and when it beats HNSW.
IVFFlat guide →Filtering
Why WHERE + LIMIT loses rows, and what iterative scans, partial indexes and B-trees do about it.
Hybrid search
Full-text plus vector search fused with RRF in one SQL query — run on real Wikipedia abstracts.
Hybrid search →halfvec & quantization
Index 3,072 dimensions, halve your storage, and what binary quantization costs in recall.
Quantization guide →Size it before you build it#
The planner turns your row count, model and recall target into index parameters, memory settings and SQL. The calculator predicts table and index size from pgvector's on-disk format — and shows its error against the indexes we built.
HNSW index size for 100K OpenAI embeddings
Measured on pgvector 0.8.7. Recall@10: vector 0.947, halfvec 0.949 (ef_search 40), binary + re-rank of 160 candidates 0.985.
| Representation | Index size | Recall@10 |
|---|---|---|
| vector | 781 MB | 0.947 |
| halfvec | 391 MB | 0.949 |
| binary quantized | 48 MB | 0.985 |
Short answers, with numbers#
What is pgvector?
pgvector is an open-source PostgreSQL extension that adds vector data types (vector, halfvec, bit, sparsevec), distance operators, and two approximate nearest-neighbour index types, HNSW and IVFFlat. It lets you store embeddings next to your relational data and search them with ordinary SQL — with transactions, joins, backups and replication working as usual.
Is pgvector fast enough for production?
For millions of vectors on one machine, yes. On our modest 4-vCPU test server, an HNSW index over 500,000 OpenAI embeddings (1,536 dimensions) answered single queries in a median of 4.1 ms at recall@10 of 0.931 with default settings. Very large or very high-throughput workloads need more hardware, partitioning or a dedicated system — see the comparison.
Should I use HNSW or IVFFlat?
HNSW for almost everyone: in our benchmark it reached higher recall at lower latency, works on an empty table and handles inserts well. IVFFlat built 9.0× faster and needs far less memory to build, which can matter for very large, rarely-updated datasets — but it must be built after loading data and needs ivfflat.probes tuned.
How many dimensions can pgvector index?
vector columns can be indexed up to 2,000 dimensions; halfvec up to 4,000; binary-quantized bit up to 64,000. For OpenAI's 3,072-dimension text-embedding-3-large, index embedding::halfvec(3072) — in our tests that index reached recall@10 of 0.979 at ef_search = 100.
Does pgvector cost anything?
No. pgvector is released under the PostgreSQL License and runs on any PostgreSQL 13 or newer you control. Managed providers include it at no extra charge; you pay for the database itself.
How we test. Everything here ran on PostgreSQL 18.6 with pgvector 0.8.7 on a 4-vCPU machine. Package versions were read from each source on 2026-10-27. We're independent of the pgvector project and of every vendor mentioned. Method · hello@pgvector.app