Quick reference

pgvector cheatsheet

Every common task as a copy-paste SQL snippet. Each card links to the full explanation in the documentation. Filter by category or search below.

Enable the extension

Enable
SQL
CREATE EXTENSION vector;

Setup →

Check the installed version

Enable
SQL
SELECT extversion FROM pg_extension WHERE extname = 'vector';

Verify →

Upgrade the extension

Enable
SQL
ALTER EXTENSION vector UPDATE;

Upgrading →

Create a table with a vector column

Store
SQL
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));

Storing →

Add a vector column to a table

Store
SQL
ALTER TABLE items ADD COLUMN embedding vector(3);

Storing →

Insert vectors

Store
SQL
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');

Storing →

Bulk load with COPY

Store
SQL
COPY items (embedding) FROM STDIN WITH (FORMAT BINARY);

Bulk loading →

Upsert a vector

Store
SQL
INSERT INTO items (id, embedding) VALUES (1, '[1,2,3]')
    ON CONFLICT (id) DO UPDATE SET embedding = EXCLUDED.embedding;

Storing →

Update and delete vectors

Store
SQL
UPDATE items SET embedding = '[1,2,3]' WHERE id = 1;
DELETE FROM items WHERE id = 1;

Storing →

Nearest neighbors (L2)

Query
SQL
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

Querying →

Nearest neighbors to a row

Query
SQL
SELECT * FROM items WHERE id != 1
    ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;

Querying →

Rows within a distance

Query
SQL
SELECT * FROM items WHERE embedding <-> '[3,1,2]' < 5;

Querying →

Compute a distance value

Query
SQL
SELECT embedding <-> '[3,1,2]' AS distance FROM items;

Querying →

Inner product (returns negative)

Query
SQL
SELECT (embedding <#> '[3,1,2]') * -1 AS inner_product FROM items;

Querying →

Cosine similarity

Query
SQL
SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;

Querying →

L1 (taxicab) distance

Query
SQL
SELECT embedding <+> '[3,1,2]' AS l1_distance FROM items;

Operators →

Hamming distance (bit)

Query
SQL
SELECT * FROM items ORDER BY embedding <~> '101' LIMIT 5;

Binary vectors →

Jaccard distance (bit)

Query
SQL
SELECT * FROM items ORDER BY embedding <%> '101' LIMIT 5;

Operators →

Average and sum vectors

Query
SQL
SELECT AVG(embedding) FROM items;
SELECT category_id, AVG(embedding) FROM items GROUP BY category_id;

Aggregates →

Filtered nearest-neighbor query

Query
SQL
SELECT * FROM items WHERE category_id = 123
    ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

Filtering →

Hybrid search with full-text search

Query
SQL
SELECT id, content FROM items, plainto_tsquery('hello search') query
    WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;

Hybrid search →

Create an HNSW index (L2)

Index
SQL
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

HNSW →

Create an HNSW index (cosine / inner product)

Index
SQL
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);

HNSW →

HNSW build options

Index
SQL
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)
    WITH (m = 16, ef_construction = 64);

HNSW →

HNSW query tuning (ef_search)

Index
SQL
SET hnsw.ef_search = 100;

BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
COMMIT;

HNSW →

Create an IVFFlat index

Index
SQL
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

IVFFlat →

IVFFlat query tuning (probes)

Index
SQL
SET ivfflat.probes = 10;

IVFFlat →

Enable iterative index scans

Filtering
SQL
SET hnsw.iterative_scan = strict_order;
SET hnsw.iterative_scan = relaxed_order;
SET ivfflat.iterative_scan = relaxed_order;

SET hnsw.max_scan_tuples = 20000;
SET hnsw.scan_mem_multiplier = 2;
SET ivfflat.max_probes = 100;

Iterative scans →

Partial index

Filtering
SQL
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WHERE (category_id = 123);

Filtering →

Partitioning

Filtering
SQL
CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);

Filtering →

Strict ordering with a materialized CTE

Filtering
SQL
WITH relaxed_results AS MATERIALIZED (
    SELECT id, embedding <-> '[1,2,3]' AS distance FROM items
    WHERE category_id = 123 ORDER BY distance LIMIT 5
) SELECT * FROM relaxed_results ORDER BY distance + 0;  -- + 0 needed for Postgres 17+

Iterative scans →

Half-precision vectors (halfvec)

Types
SQL
CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3));
SELECT * FROM items ORDER BY embedding <-> '[1,2,3]' LIMIT 5;

Half precision →

Half-precision index over a full-precision column

Types
SQL
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
SELECT * FROM items ORDER BY embedding::halfvec(3) <-> '[1,2,3]' LIMIT 5;

Half precision →

Binary vectors (bit)

Types
SQL
CREATE TABLE items (id bigserial PRIMARY KEY, embedding bit(3));
INSERT INTO items (embedding) VALUES ('000'), ('111');

Binary vectors →

Binary quantization with re-ranking

Types
SQL
CREATE INDEX ON items USING hnsw ((binary_quantize(embedding)::bit(3)) bit_hamming_ops);

SELECT * FROM (
    SELECT * FROM items
    ORDER BY binary_quantize(embedding)::bit(3) <~> binary_quantize('[1,-2,3]') LIMIT 20
) ORDER BY embedding <=> '[1,-2,3]' LIMIT 5;

Quantization →

Sparse vectors (sparsevec)

Types
SQL
CREATE TABLE items (id bigserial PRIMARY KEY, embedding sparsevec(5));
INSERT INTO items (embedding) VALUES ('{1:1,3:2,5:3}/5'), ('{1:4,3:5,5:6}/5');
SELECT * FROM items ORDER BY embedding <-> '{1:3,3:1,5:2}/5' LIMIT 5;

Sparse vectors →

Subvector index

Types
SQL
CREATE INDEX ON items USING hnsw ((subvector(embedding, 1, 3)::vector(3)) vector_cosine_ops);

Subvector →

Debug a query with EXPLAIN

Performance
SQL
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

Performance →

Raise memory for index builds

Performance
SQL
SET maintenance_work_mem = '8GB';

Build time →

Parallel index build workers

Performance
SQL
SET max_parallel_maintenance_workers = 7;  -- plus leader

Build time →

Create an index without blocking writes

Performance
SQL
CREATE INDEX CONCURRENTLY ON items USING hnsw (embedding vector_l2_ops);

Indexing →

Speed up vacuum with a reindex

Performance
SQL
REINDEX INDEX CONCURRENTLY index_name;
VACUUM table_name;

Vacuuming →

Speed up exact search

Performance
SQL
SET max_parallel_workers_per_gather = 4;

Performance →

Measure recall against exact search

Performance
SQL
BEGIN;
SET LOCAL enable_indexscan = off;  -- force exact search
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
COMMIT;

Monitoring →

Check index size

Performance
SQL
SELECT pg_size_pretty(pg_relation_size('index_name'));

Monitoring →

Need values for your own table? The index planner computes the right index, tuning values, and storage estimate. For explanations behind each snippet, read the documentation. Stuck on an error? See the troubleshooting guide.