Skip to main content

Overview

pgvector adds vector similarity search to PostgreSQL, letting you store embeddings from OpenAI, Cohere, Hugging Face, or any other model alongside your relational data. pgvectorscale builds on pgvector with StreamingDiskANN indexes for larger, disk-oriented vector workloads. Both extensions are enabled by default on new Rivestack databases. Their SQL extension names are vector and vectorscale.

Verify the extension

Confirm both extensions are active on your database:

Store embeddings

Create a table with a vector column

The VECTOR(n) type stores n-dimensional vectors. Common dimension sizes:

Insert vectors

From Python with OpenAI

Query vectors

Find the 5 most similar documents using cosine distance:

Distance operators

Create an index

For tables with more than a few thousand rows, create an index to speed up queries:
HNSW provides fast, approximate nearest-neighbor search with good recall. Tuning parameters: Set the search parameter at query time. Higher ef_search means better recall and higher latency (the default is 40):
A plain session SET hnsw.ef_search is silently ignored. Every dedicated plan (Solo, Starter, Growth, Scale) connects through PgBouncer in transaction-pooling mode on port 6432, so a bare SET hnsw.ef_search = 100; runs in its own transaction and is reset before your next query, leaving you with the default (40) instead. Always either use SET LOCAL inside the same transaction as the query, or set a persistent default with ALTER DATABASE appdb SET hnsw.ef_search = … (or ALTER ROLE appdb SET …).Free databases connect directly to PostgreSQL on port 5432, where a plain session SET works normally. This holds on HA clusters too. The load balancer and source-filtering HAProxy gateway pass the TLS stream to PgBouncer rather than to PostgreSQL directly, so scaling up does not turn session-level SET back on.

IVFFlat index

IVFFlat requires a training step and works best when you set lists to rows / 1000 for tables up to 1M rows.

StreamingDiskANN index (pgvectorscale)

For datasets that should not keep the entire graph in memory, use pgvectorscale’s StreamingDiskANN index:
The table still uses pgvector’s VECTOR type and distance operators; pgvectorscale supplies the diskann index access method. Test recall, build time, memory, and latency with your own embeddings before choosing an index for production.

Which index to use?

RAG example

A complete retrieval-augmented generation (RAG) pattern:

Benchmarks

Measured pgvector performance across the tiers (AMD CPX, shared vCPU, local NVMe), 250,000 vectors at 1536 dimensions, HNSW m=16 / ef_construction=64, cosine, from a same-region client over PgBouncer (:6432) and TLS, recall@10 vs exact KNN: Scale also builds and serves a 1M × 1536 index (~6 GB) hot: ~3,600 QPS at recall@10 0.74, p50 4.2 ms, 16 clients (index builds in ~9 min).
CPX is AMD EPYC shared vCPU (not CPU-isolated); the gain over the older Intel CX line is faster cores and far better availability. QPS and p50 latency trade off across the concurrency curve, so each figure carries its recall and client count. Same-region network floor is ~0.3 to 0.5 ms per round-trip. Every operating point, with one-command reproduce steps: measured pgvector benchmarks.

Performance tips

  • Always create an index for tables over a few thousand rows. Without an index, pgvector scans every row.
  • Use HNSW as your default index type. It offers the best recall/speed trade-off.
  • Benchmark StreamingDiskANN when the vector graph is too large to keep comfortably in memory.
  • Increase ef_search if recall is too low. Start with 100 and increase as needed, but set it with SET LOCAL inside the query’s transaction or via ALTER DATABASE … SET — every plan pools on :6432, and a plain session SET is dropped by transaction pooling. The same applies to ivfflat.probes.
  • Batch inserts for loading large datasets. Use COPY or multi-row INSERT for best throughput.
  • Choose the right distance operator for your use case. Cosine (<=>) is the most common for text embeddings.