Recommended Free Tools
Start with the plan, not another index or a larger search setting. Run EXPLAIN (ANALYZE, BUFFERS) on the slow query, then check whether PostgreSQL uses the intended vector index, whether the distance operator matches that index’s operator class, and how many rows a filter removes. The right fix depends on what the plan shows—and, for approximate search, on how much recall you can trade for latency.
Why is my pgvector query slow?
Inspect the exact query that is slow, including its filters, ordering, and limit. PostgreSQL’s EXPLAIN output compares estimated and actual row counts; ANALYZE runs the query and reports actual execution details, while BUFFERS shows buffer activity. pgvector recommends this form for performance troubleshooting.
As an Amazon Associate I earn from qualifying purchases.
EXPLAIN (ANALYZE, BUFFERS)
SELECT id
FROM items
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10;
In the plan, find the scan and sort nodes, whether the intended index appears, actual versus estimated rows, rows removed by filters, and where execution time and buffer activity accumulate. A slow query does not by itself prove that an index is missing: the plan may be doing exact search, using a different path because of selectivity, or scanning many approximate candidates before filters leave enough results.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsCheck the operator and operator class
The distance operator in ORDER BY must correspond to the operator class used to build the vector index. pgvector has separate operator classes for L2 distance, inner product, cosine distance, and other distance functions. If an application needs multiple distance functions, create an index for each one it uses.
#1 Best Overall
| Distance used in the query | Matching pgvector operator class |
|---|---|
L2 distance, <-> |
vector_l2_ops |
Cosine distance, <=> |
vector_cosine_ops |
Negative inner product, <#> |
vector_ip_ops |
For example, an HNSW index for L2 distance can be created with CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);. Confirm that the application orders by the same distance operator. A mismatched operator and operator class can prevent the intended nearest-neighbor index path.
Should you use exact search, HNSW, or IVFFlat?
pgvector uses exact nearest-neighbor search by default; it provides perfect recall, but may take longer as the candidate set grows. HNSW and IVFFlat are approximate alternatives: they trade some recall for speed. Compare them on representative data and queries rather than assuming an index or setting will improve your workload.
| Approach | Recall and query trade-off | Build and memory profile | Useful starting points |
|---|---|---|---|
| Exact search | Perfect recall; can be a good fit when the filtered subset is small or perfect recall is required. | No approximate vector index is needed for the exact search itself. A conventional index on filter columns may help narrow the subset. | For exact search without a vector index, pgvector says raising max_parallel_workers_per_gather can improve speed. For unit-normalized vectors, its documentation recommends inner product for best performance. |
| HNSW | Generally stronger speed/recall trade-off than IVFFlat; raising hnsw.ef_search generally improves recall at a query-time cost. |
Slower index builds and higher memory use than IVFFlat. Can be created before the table contains data. | Documented defaults: m = 16, ef_construction = 64, and hnsw.ef_search = 40. |
| IVFFlat | Generally lower query performance in the speed/recall trade-off than HNSW; increasing ivfflat.probes improves recall at a speed cost. |
Faster builds and lower memory use than HNSW. Build after representative data is present. | Project heuristics: lists around rows / 1,000 up to one million rows, and around the square root of row count above that; start probes around the square root of lists. These are starting points, not universal optima. |
Measure query latency, recall, index build time, memory footprint, filtered-result yield, and the impact of writes and maintenance. Compare approximate results with an exact-search baseline on representative queries so you can see which neighbors are lost; adding an approximate index can change the returned neighbors.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Tune HNSW per query
Test higher search breadth in a transaction so the change applies only to that transaction:
BEGIN;
SET LOCAL hnsw.ef_search = 100;
SELECT id
FROM items
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10;
COMMIT;
Compare the plan, latency, and recall with the default ef_search of 40. A higher value generally examines more candidates and can improve recall, but it may also increase query work.
Choose IVFFlat lists and probes from your data
IVFFlat works best when built after representative rows have been loaded. Use the project’s row-count heuristics only to pick an initial lists value, then test ivfflat.probes against actual query latency and recall. Increasing probes searches more lists and generally improves recall at a speed cost; neither heuristic guarantees the best setting for a particular dataset.
Rank #3
Why does a filtered vector query return too few results?
With an approximate index, pgvector applies metadata filters after scanning the ANN index. The project’s example illustrates the effect: if a filter matches 10% of rows and HNSW uses its default ef_search of 40, only four matching rows are expected on average. A query asking for more than that can return too few results, even though the unfiltered ANN scan appears to work.
Free tools Windows power users keep installed
One-click scans. No signup required.
Use the plan to see whether the filter is selective and how many scanned rows it removes. Then choose a remedy based on how many distinct filter values you have and how much extra search work is acceptable.
Use iterative scans when available
Iterative index scans were introduced in pgvector 0.8.0. In pgvector 0.8.0 and later, they let an approximate scan continue until it finds enough matching rows or reaches a configured limit. Strict ordering preserves distance order; relaxed ordering can return results slightly out of order and may improve recall.
BEGIN;
SET LOCAL hnsw.iterative_scan = strict_order;
SELECT id
FROM items
WHERE category_id = 42
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10;
COMMIT;
For HNSW, iterative scans have a documented hnsw.max_scan_tuples default of 20,000 and hnsw.scan_mem_multiplier default of 1. For IVFFlat, ivfflat.max_probes bounds probes. Raising these limits can require more work or memory; test the resulting plan and recall instead of raising them without measurement.
If you use relaxed ordering but need strict final distance order, pgvector documents sorting the materialized results afterward. Its example requires distance + 0 on PostgreSQL 17 and later:
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →WITH relaxed_results AS MATERIALIZED (
SELECT id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM items
WHERE category_id = 42
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10
)
SELECT id, distance
FROM relaxed_results
ORDER BY distance + 0;
Use filter indexes, partial indexes, or partitioning
For a highly selective filter, a conventional index on the filter column may let PostgreSQL find the matching subset and perform exact distance ordering within it. For queries filtering on several columns, consider an appropriate multicolumn index. This can be preferable to making an approximate scan search much farther.
- Few distinct filter values: consider partial vector indexes for the relevant values.
- Many distinct filter values: consider partitioning so a query searches a smaller relevant portion of the data.
- Tenant isolation: pgvector recommends list partitioning or separate tables. A shared approximate index can let one tenant’s vectors affect another tenant’s query speed and recall.
For a distance threshold, pgvector documents placing the threshold outside a materialized nearest-results CTE while keeping other filters inside it. This separates candidate selection from threshold filtering.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How should memory, loading, and index maintenance affect the fix?
If index size or memory pressure is the bottleneck, pgvector documents halfvec for a smaller working set and binary quantization with reranking for smaller indexes at scale. These approaches can change accuracy, so compare recall as well as resource use before adopting them.
- Bulk loading: use
COPYfor bulk data, then add indexes after the initial load for best performance. - Writes during index creation:
CREATE INDEX CONCURRENTLYavoids blocking writes, though it still has operational constraints. - HNSW vacuuming: vacuuming an HNSW index can take time; pgvector suggests reindexing concurrently before vacuuming to speed that process.
If query and index changes are not enough at your scale, pgvector names PostgreSQL replicas, Citus, and PgDog as possible scaling approaches. Treat infrastructure changes as a separate decision and benchmark end-to-end workload behavior.
Which pgvector version do you have?
Check the installed extension version before relying on release-specific features:
SELECT extversion
FROM pg_extension
WHERE extname = 'vector';
The pgvector changelog lists version 0.8.7, dated 2026-10-01, and records an IVFFlat index-build buffer-overflow fix. It lists version 0.8.0, dated 2024-10-30, as introducing iterative index scans and improvements to filtering cost estimation and HNSW query performance. Those release notes do not establish that upgrading will make a particular workload faster; verify compatibility and measure the workload after any upgrade.
Quick Recap
A practical order for troubleshooting
- Capture the actual slow query and run
EXPLAIN (ANALYZE, BUFFERS). - Check estimated versus actual rows, index usage, rows removed by filters, and where time and buffer activity accumulate.
- Verify the query’s distance operator matches the vector index’s operator class.
- Decide whether exact search is acceptable or whether the workload warrants approximate search.
- For filtered ANN queries, test iterative scans and their limits; if filter selectivity or tenant boundaries call for it, test filter indexes, partial indexes, or partitioning.
- Compare latency, recall, result yield, memory, build time, and maintenance cost on representative data before keeping the change.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




