All skills
simota avatar

/tuner

@e307415
by shingo imotasimota/agent-skills85 stars
15

Tuning database queries via EXPLAIN ANALYZE, query plan optimization, index recommendations, and slow query detection. Not for schema/migrations (Schema) or non-DB performance (Bolt).

Use this Skill: https://skilld.dev/gh/simota/agent-skills/tuner

This session only. Nothing lands on disk.

referencevector-search-query-optimization.md

≈2.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Vector Search Query Optimization

Purpose: Use this file when optimizing pgvector queries, tuning HNSW/IVFFlat indexes, or diagnosing filtered vector search performance.

Contents:

  • 2026-05 pgvector version posture
  • pgvector 0.8.0 Iterative Scan
  • HNSW vs IVFFlat comparison
  • Index parameter tuning
  • Filter optimization patterns
  • EXPLAIN ANALYZE for vector queries
  • Production recommended settings

2026-05 pgvector Version Posture

The supported pgvector lineage as of 2026-05:

Version Headline change When to choose
0.7.x halfvec (2-byte floats, up to 4000 dims), sparsevec (up to 1000 nonzero dims), bit binary vectors (up to 64000 dims); scalar quantization Reduce storage/memory 50%+ for float32 embeddings via halfvec (https://www.postgresql.org/about/news/pgvector-070-released-2852/)
0.8.x HNSW iterative scan (hnsw.iterative_scan), parallel HNSW build; up to 5.7× QPS improvement for filtered queries vs 0.7.4 Production default if managed service supports it (Aurora pgvector 0.8.0 available since 2025; https://aws.amazon.com/blogs/database/supercharging-vector-search-performance-and-relevance-with-pgvector-0-8-0-on-amazon-aurora-postgresql/)
0.9.x (early 2026) IVFFlat improvements, sparse vector support, further speed boosts (https://callsphere.ai/blog/vector-database-benchmarks-2026-pgvector-qdrant-weaviate-milvus-lancedb) When self-managing PG and the dataset has high filter selectivity, sparse-vector use cases, or large IVFFlat indexes

Benchmarks (1M vectors, ann-benchmarks-style):

  • pgvector HNSW @ ef_search=100: p50 ≈ 2.1ms, p99 ≈ 4.3ms, recall@10 ≈ 0.971.
  • Qdrant default HNSW: p50 ≈ 1.8ms, p99 ≈ 3.6ms, recall@10 ≈ 0.978.
  • HNSW parallel build (PG17+ background workers) cut build time 30–50% on multi-core hosts for 1M-vector indexes (https://callsphere.ai/blog/vector-database-benchmarks-2026-pgvector-qdrant-weaviate-milvus-lancedb).

Trade-off rule: stay on pgvector when the workload is dominated by hybrid relational+vector queries inside one transaction. Move to a dedicated vector DB (Qdrant, Weaviate, Milvus, LanceDB) only when (a) raw QPS is the binding constraint, (b) the recall budget is tighter than what HNSW + iterative scan delivers, or (c) sparse + dense + lexical fusion is required.

For TimescaleDB-style time-series + vector hybrid workloads, Timescale rebranded to Tiger Data in June 2025 (https://www.tigerdata.com/blog/timescale-becomes-tigerdata); the vector extension is now pgvectorscale (Streaming DiskANN) and ships alongside Hypercore (hybrid row/columnar engine) on Tiger Cloud.


pgvector 0.8.0: Iterative Scan

pgvector 0.8.0 introduced Iterative Scan for HNSW indexes, enabling accurate filtered vector search by progressively expanding the search until enough results meeting the filter condition are found.

New Parameters

Parameter Default Description
hnsw.iterative_scan off Enable iterative scan: off, relaxed_order, strict_order
hnsw.max_scan_tuples 20000 Maximum tuples to scan per query
hnsw.scan_mem_multiplier 1.0 Memory multiplier for scan buffer

Iterative Scan Modes

Mode Behavior Use when
off Standard HNSW scan (no iteration) No WHERE filter on vector queries
relaxed_order Results may not be strictly ordered by distance Acceptable for approximate nearest-neighbor with filter
strict_order Strict distance ordering preserved Exact order required with filter
-- Enable iterative scan for filtered vector search
SET hnsw.iterative_scan = 'relaxed_order';
SET hnsw.max_scan_tuples = 50000;

SELECT id, content, embedding <=> '[0.1, 0.2, ...]' AS distance
FROM documents
WHERE category = 'technical'
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 10;

HNSW vs IVFFlat Comparison

Metric HNSW IVFFlat
Query latency (1M rows) ~1-5ms ~5-20ms
Recall @ 10 (default params) ~95-99% ~85-95%
Memory usage High (graph stored in RAM) Low (only centroids in RAM)
Build time Slow (O(n log n)) Fast (O(n))
Update performance Good (incremental insert) Poor (requires rebuild for accuracy)
Filter support (pre-0.8) Poor without iterative scan Moderate with probes tuning
Filter support (0.8+) Good with iterative scan Good with probes tuning
Best for Online search, fresh data, high recall Batch workloads, static data, memory-limited

Index Parameter Tuning

HNSW Parameters

Parameter Default Range Effect
m 16 4–100 Graph connectivity; higher = better recall, more memory
ef_construction 64 4–1000 Build quality; higher = better recall, slower build
ef_search 40 1–1000 Query quality; higher = better recall, slower query
-- High-recall HNSW index
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 32, ef_construction = 128);

-- Query tuning
SET hnsw.ef_search = 100;

IVFFlat Parameters

Parameter Default Range Effect
lists 100 1–10000 Number of clusters; rule: sqrt(row_count)
probes 1 1–lists Clusters searched at query time; higher = better recall
-- IVFFlat for 1M rows
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 1000);

-- Query tuning (balance recall vs speed)
SET ivfflat.probes = 10;

Rule of Thumb

HNSW:
  m = 16 (default)    → general purpose
  m = 32–64           → high recall requirement
  ef_construction = 64–128 → standard build
  ef_search = 40–200  → runtime tuning without rebuild

IVFFlat:
  lists = sqrt(row_count)    → starting point
  probes = lists * 0.05–0.1  → 5-10% of lists for good recall

Filter Optimization Patterns

Pre-filter vs Post-filter

Strategy How it works When to use
Post-filter ANN search → filter results Default; filter selectivity > 50%
Pre-filter Filter rows → exact search on subset Small filtered set (< 10K rows)
Iterative scan (pgvector 0.8+) ANN search → expand until filter satisfied Medium selectivity, HNSW index
Composite index Separate btree index on filter column High-cardinality filter, partition by filter value

Post-filter (default behavior)

-- pgvector defaults to ANN then filter
SELECT id, content
FROM documents
WHERE embedding <=> '[...]' < 0.5  -- distance threshold
  AND category = 'technical'
ORDER BY embedding <=> '[...]'
LIMIT 10;

Pre-filter with Subquery

-- Effective when category has very few matching rows
SELECT id, content, embedding <=> '[...]' AS distance
FROM (
  SELECT * FROM documents WHERE category = 'technical' AND active = true
) filtered
ORDER BY embedding <=> '[...]'
LIMIT 10;

Partition by Filter Value

-- Partition table by category for large datasets
CREATE TABLE documents_technical PARTITION OF documents
FOR VALUES IN ('technical');

-- Query hits only one partition
SELECT id, content, embedding <=> '[...]' AS distance
FROM documents
WHERE category = 'technical'
ORDER BY embedding <=> '[...]'
LIMIT 10;

EXPLAIN ANALYZE for Vector Queries

-- Analyze vector search plan
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT id, content, embedding <=> '[0.1, 0.2, ...]' AS distance
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 10;

Key Plan Nodes to Look For

Node Meaning Action
Index Scan using hnsw_idx HNSW index used Check ef_search if recall is low
Index Scan using ivfflat_idx IVFFlat index used Increase probes if recall is low
Seq Scan No index used Check enable_seqscan, index existence
rows=X (actual X) Estimate accuracy Large mismatch → run ANALYZE

Diagnosing Low Recall

-- Check actual vs approximate results
WITH exact AS (
  SELECT id, embedding <-> '[...]' AS dist
  FROM documents ORDER BY dist LIMIT 10
),
approx AS (
  SELECT id, embedding <-> '[...]' AS dist
  FROM documents ORDER BY dist LIMIT 10
)
SELECT COUNT(*) AS overlap
FROM exact e JOIN approx a USING (id);
-- overlap < 8 → tune ef_search or probes

Production Recommended Settings

-- postgresql.conf tuning for pgvector workloads
shared_buffers = '25% of RAM'          -- keep HNSW graph in buffer cache
work_mem = '256MB'                      -- for sort during IVFFlat build
maintenance_work_mem = '2GB'            -- for index build operations
max_parallel_workers_per_gather = 4     -- parallel index scans

-- Session-level for query tuning
SET hnsw.ef_search = 100;
SET hnsw.iterative_scan = 'relaxed_order';
SET hnsw.max_scan_tuples = 50000;
SET ivfflat.probes = 20;

Index Creation Best Practices

-- Always use CONCURRENTLY in production
CREATE INDEX CONCURRENTLY ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- Monitor build progress
SELECT phase, blocks_done, blocks_total,
       tuples_done, tuples_total
FROM pg_stat_progress_create_index
WHERE relid = 'documents'::regclass;

Monitoring Vector Index Health

-- Index size
SELECT pg_size_pretty(pg_relation_size('hnsw_idx')) AS index_size;

-- Cache hit ratio for index
SELECT idx_blks_hit::float / NULLIF(idx_blks_hit + idx_blks_read, 0) AS hit_ratio
FROM pg_statio_user_indexes
WHERE indexrelname = 'hnsw_idx';

-- Slow vector queries
SELECT query, mean_exec_time, calls
FROM pg_stat_statements
WHERE query LIKE '%<=>%' OR query LIKE '%<->%'
ORDER BY mean_exec_time DESC
LIMIT 10;

Source: SKILL.md on GitHub

1 warning13d5 checks · Risk SAFE
  • Gen Agent Trust Hub13d

    The skill is a database tuning specialist designed to analyze query performance and recommend optimizations. No malicious code, exfiltration patterns, or obfuscation were detected. A low-severity finding for indirect prompt injection is noted due to the skill's primary function of ingesting and transforming potentially untrusted data like query plans and logs into actionable prompts for other agents.

  • Socket13d

    No alerts

  • Snyk13d

    Risk: LOW · No issues

  • Runlayer6mo

    4/13 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at e307415. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 2 weeks ago

README badge

README badge for simota/agent-skills/tuner