Skip to content

perf(postgres): optimize PgMemoryStore for throughput and query efficiency#1

Open
ZhangHuiGui wants to merge 1 commit into
Dontpushme:mainfrom
ZhangHuiGui:perf/postgres-store-optimization
Open

perf(postgres): optimize PgMemoryStore for throughput and query efficiency#1
ZhangHuiGui wants to merge 1 commit into
Dontpushme:mainfrom
ZhangHuiGui:perf/postgres-store-optimization

Conversation

@ZhangHuiGui

Copy link
Copy Markdown

Summary

Six targeted performance improvements to the PostgreSQL memory store (src/core/store/postgres.ts), reducing latency and improving throughput for high-frequency operations.

Changes

1. Batch Transaction Writes (upsertL1Batch / upsertL0Batch)

  • Wrap multi-record inserts in a single BEGIN/COMMIT transaction
  • Eliminates per-row connection acquisition and network round-trips
  • Falls back to single-record path when batch size is 1

2. Hybrid Search SQL Rewrite (searchL1HybridNative)

  • Carry all columns through CTEs, eliminating the final JOIN back to the main table
  • Add WHERE content <@> to_bm25query(...) > 0 to exclude zero-relevance BM25 results from RRF fusion
  • Use named prepared statement for server-side plan caching

3. Named Prepared Statements for High-Frequency Searches

  • search_l1_vector_v1, search_l1_fts_v1
  • search_l0_vector_v1, search_l0_fts_v1
  • l1_hybrid_native_v2

Avoids repeated parse+plan overhead on every call.

4. Concurrent Reindexing (reindexAll)

  • Replace serial embed+update loop with paginated reads
  • Bounded-parallelism embedding (CONCURRENCY=4, Promise.allSettled)
  • Batched UPDATE via unnest() arrays instead of per-row UPDATE

5. VACUUM ANALYZE After Bulk Deletes

  • Fire-and-forget VACUUM ANALYZE when >50 rows are deleted
  • Prevents DiskANN/HNSW index bloat from dead tuples

6. BM25 Query Normalization Improvement

  • Add Chinese stopword filtering (60+ high-frequency function words)
  • Filter single-character CJK tokens (too generic for BM25 precision)
  • Cap token count at MAX_BM25_TOKENS=8 to maintain query precision

Impact

Area Before After
Batch write (10 records) 10 round-trips 1 transaction
Hybrid search 2 table scans (CTE + JOIN) 1 scan (CTE only)
Reindex 1000 records ~1000 sequential API calls 4-way parallel + batched UPDATE
Search plan caching None (re-parse every call) Server-side prepared statements

Testing

  • Zero TypeScript lint errors after all changes
  • Backward compatible: single-record paths unchanged
  • Graceful degradation: all try/catch patterns preserved

…iency

Six targeted performance improvements to the PostgreSQL memory store:

1. Batch transaction writes (upsertL1Batch / upsertL0Batch):
   - Wrap multi-record inserts in a single BEGIN/COMMIT transaction
   - Eliminates per-row connection acquisition and network round-trips
   - Falls back to single-record path when batch size is 1

2. Hybrid search SQL rewrite (searchL1HybridNative):
   - Carry all columns through CTEs, eliminating the final JOIN back to
     the main table (saves a full table scan on large datasets)
   - Add WHERE content <@> to_bm25query(...) > 0 to exclude zero-relevance
     BM25 results from RRF fusion
   - Use named prepared statement for server-side plan caching

3. Named prepared statements for high-frequency searches:
   - search_l1_vector_v1, search_l1_fts_v1
   - search_l0_vector_v1, search_l0_fts_v1
   - l1_hybrid_native_v2
   Avoids repeated parse+plan overhead on every call.

4. Concurrent reindexing (reindexAll):
   - Replace serial embed+update loop with paginated reads
   - Bounded-parallelism embedding (CONCURRENCY=4, Promise.allSettled)
   - Batched UPDATE via unnest() arrays instead of per-row UPDATE

5. VACUUM ANALYZE after bulk deletes (deleteL1Expired / deleteL0Expired):
   - Fire-and-forget VACUUM ANALYZE when >50 rows are deleted
   - Prevents DiskANN/HNSW index bloat from dead tuples

6. BM25 query normalization improvement:
   - Add Chinese stopword filtering (60+ high-frequency function words)
   - Filter single-character CJK tokens (too generic for BM25 precision)
   - Cap token count at MAX_BM25_TOKENS=8 to maintain query precision
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant