All Products
Search
Document Center

PolarDB:Approximate indexes

Last Updated:Mar 28, 2026

By default, pgvector performs exact nearest neighbor searches with perfect recall. To increase search speed, add an approximate index — this trades a small amount of recall for significantly higher throughput. Two index types are supported: Hierarchical Navigable Small Worlds (HNSW) and Inverted File with Flat Compression (IVFFlat).

Choose an index type

Use this table to choose the right index for your use case.

HNSWIVFFlat
Build timeLongerShorter
Memory usageHigherLower
Query performanceBetter speed-recall tradeoffLower speed-recall tradeoff
Requires existing dataNoYes
Handles data additionsAutomaticallyRequires rebuild for best recall

HNSW is the recommended default. It delivers better query performance and handles new data without rebuilding. Use IVFFlat when build time or memory usage is a constraint.

HNSW

HNSW builds a multilayer graph structure. It does not require training and can be created on an empty table.

Create an HNSW index

Create a separate index for each distance function you plan to use in queries. The following table shows the available distance functions and their corresponding operator classes.

Distance functionQuery operatorOperator class
Euclidean distance (L2)<->vector_l2_ops
Inner product<#>vector_ip_ops
Cosine distance<=>vector_cosine_ops
Manhattan distance (L1)<+>vector_l1_ops
Hamming distance<~>bit_hamming_ops
Jaccard distance<%>bit_jaccard_ops

Examples

-- Euclidean distance (L2)
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

-- Inner product
CREATE INDEX ON items USING hnsw (embedding vector_ip_ops);

-- Cosine distance
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);

-- Manhattan distance (L1)
CREATE INDEX ON items USING hnsw (embedding vector_l1_ops);

-- Hamming distance
CREATE INDEX ON items USING hnsw (embedding bit_hamming_ops);

-- Jaccard distance
CREATE INDEX ON items USING hnsw (embedding bit_jaccard_ops);
The operator class depends on the vector type. For halfvec columns, use halfvec_l2_ops instead of vector_l2_ops. For sparsevec columns, use sparsevec_l2_ops.

Supported vector types

Vector typeDescription
vectorUp to 2,000 dimensions
halfvecHalf-precision vectors, up to 4,000 dimensions
sparsevecSparse vectors, up to 1,000 non-zero elements
bitBinary vectors, up to 64,000 dimensions

Index creation options

ParameterDefaultDescription
m16Maximum number of connections per layer. Higher values improve recall but slow down indexing.
ef_construction64Size of the dynamic candidate list used during graph construction. Higher values improve index quality and recall but increase build time.
CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 16, ef_construction = 64);

Query options

ParameterDefaultDescription
hnsw.ef_search40Size of the dynamic candidate list used during search. Higher values improve recall but slow down queries.

Set hnsw.ef_search for the current session:

SET hnsw.ef_search = 100;

To apply the setting to a single query only, use SET LOCAL inside a transaction:

BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT ...
COMMIT;

IVFFlat

IVFFlat divides vectors into lists and searches the subset of lists closest to the query vector. Build times are shorter and memory usage is lower than HNSW, but query performance in the speed-recall tradeoff is lower.

IVFFlat requires training data. Create the index after the table has data; an index built on an empty table will have poor recall.

Optimize for recall

Follow these three steps to get good recall from an IVFFlat index:

  1. Create the index after loading data. The index uses k-means clustering on existing rows — an empty table produces a poor index.

  2. Choose the number of lists. Use rows / 1000 for datasets up to 1 million rows, and sqrt(rows) for datasets larger than 1 million rows.

  3. Set the number of probes at query time. Start with sqrt(lists). More probes improve recall but slow down queries. Setting probes equal to the number of lists triggers an exact nearest neighbor search, but the query planner will not use the index in that case.

Create an IVFFlat index

Distance functionQuery operatorOperator class
Euclidean distance (L2)<->vector_l2_ops
Inner product<#>vector_ip_ops
Cosine distance<=>vector_cosine_ops
Hamming distance<~>bit_hamming_ops
IVFFlat does not support Manhattan distance (L1) or Jaccard distance. For halfvec columns, use halfvec_l2_ops. For sparsevec columns, use sparsevec_l2_ops.

Examples

-- Euclidean distance (L2)
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);

-- Inner product
CREATE INDEX ON items USING ivfflat (embedding vector_ip_ops) WITH (lists = 100);

-- Cosine distance
CREATE INDEX ON items USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

-- Hamming distance
CREATE INDEX ON items USING ivfflat (embedding bit_hamming_ops) WITH (lists = 100);

Supported vector types

Vector typeDescription
vectorUp to 2,000 dimensions
halfvecHalf-precision vectors, up to 4,000 dimensions
bitBinary vectors, up to 64,000 dimensions

Query options

ParameterDefaultDescription
ivfflat.probes1Number of lists to search. Higher values improve recall but slow down queries.

Set ivfflat.probes for a single query using SET LOCAL:

BEGIN;
SET LOCAL ivfflat.probes = 10;
SELECT ...
COMMIT;

Speed up index building

Two parameters control index build performance.

ParameterDefaultDescription
maintenance_work_memMaximum memory allocated for index building. Adjust the parameter based on the cluster specifications. If the graph fits into maintenance_work_mem, the index building speed is faster. Specify an appropriate value to prevent memory exhaustion of the server.
max_parallel_maintenance_workers2Number of parallel workers used during index creation. Increase this to speed up builds.

If the HNSW graph no longer fits in maintenance_work_mem, the build continues but is significantly slower:

NOTICE: hnsw graph no longer fits into maintenance_work_mem after 100000 tuples
DETAIL: Building takes significantly more time.
HINT: Increase maintenance_work_mem to speed up building.

To use more parallel workers:

SET max_parallel_maintenance_workers = 7; -- plus leader thread
To use more than the default number of workers, also increase max_parallel_workers (default: 8).

Creating the index after loading your initial data is faster than building incrementally. The index creation options (m, ef_construction, lists) also significantly affect build time.

Monitor index building progress

Query the pg_stat_progress_create_index view to track build progress.

HNSW build phases

  1. initializing

  2. loading tuples

IVFFlat build phases

  1. initializing

  2. performing k-means

  3. assigning tuples

  4. loading tuples

-- Monitor HNSW build progress
SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;

-- Monitor IVFFlat build progress
SELECT phase, round(100.0 * tuples_done / nullif(tuples_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
The % field is updated only during the loading tuples phase.