Repository navigation
v0.60.129.0 perf(postgres): retrieval tracking off pages, partial indexes for serve-loop persistence reads, small-source vector walk skip - #6375
Merged
Conversation
…es to page_retrievals Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…twins; goldens; docs Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…py/pg-write-storage-wave
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…ump locks nothing Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…of pages A source scope holding a small share of pages never fills the walk's window (the nearest chunks overall belong to other sources), so the walk ran, came back short and the joined statement ran anyway. Both engines now read pages.source_id planner statistics (pg_stats MCV list, cached for a minute, only for scoped searches) and buildVectorSearchStatement omits indexWalkSql when the scope's page share is below INDEX_WALK_MIN_SCOPE_SHARE (0.1). The joined, exact and hasMore statements and their parameters are byte-identical; missing statistics keep the walk. Synthetic 50k brain (Postgres 16.15 + pgvector 0.8.7), remote search on a 0.1% source: 33-41 -> 10-18 ms p50; PGLite 5k: 33-34 -> 12-13 ms p50. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…py/pg-write-storage-wave
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
|
😎 This pull request was merged. |
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…, sql-text and upgrade-replay goldens; v224 trigger body matches schema.sql Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Efficiency wave 2 (GBRA-70), following #6364. Reads stop writing to
pages, the two persistence reads a residentgbrain serverepeats stop scanning every write receipt ever stored, and a source-scoped vector search on a small source skips the index walk. Every number below comes from synthetic brains; no real brain data was used.What changed
Retrieval tracking moves to
page_retrievals(v224). The per-readUPDATE pages SET last_retrieved_athit an indexed column, so it was never HOT. Each one wrote a new wide tuple plus entries in all 22 pages indexes and fired 7 triggers. Its statement trigger also advancedpage_generation_clock_seqeven when the 5-minute throttle matched no row, which invalidated the query-cache bookmark, the get_health memo and the projection-readiness memo on every read. The bump is now a pre-filtered upsert into a narrow side table:volunteerUsageStats, entity card) takeGREATEST(pages.last_retrieved_at, page_retrievals.last_retrieved_at). The migration copies the column, keeps its values and drops its unused index CONCURRENTLY.Serve-loop persistence indexes (v223).
managed_sync_*, that meant a full walk that detoasted every intent.intentafter 30 days), so the walk grew with every write. That is why it scaled with brain size, and retention itself is working as intended.persistence_requests_sync_watermarkreplaces v222's index.compactWriteReceipts' candidate scan was a sequential scan, andpersistence_requests_compactablereplaces it.buildIndexOnline.Small-source vector scope.
pages.source_idstatistics from pg_stats, cached for 60 s and only for source-scoped searches.buildVectorSearchStatementomitsindexWalkSql. The joined, exact and hasMore statements stay byte-identical, and missing statistics keep the walk.Numbers
All runs: 4 vCPU / 16 GiB, Postgres 16.15 + pgvector 0.8.7, warm and prewarmed. Brains are 5,001 pages / 25,331 chunks and 50,010 pages / 248,802 chunks. Values are p50 ms, with pgbench N in brackets.
A mixed serve workload ran for 150 s over stdio MCP (
get_page×4,search,list_pages,query,put_pageper cycle, with pg_stat_statements):last_retrieved_atUPDATE share of WALTool p50/p95 didn't move, since the bump is fire-and-forget.
Migration runtime at 50k: v223's watermark build took 2.3 s and the compactable build 0.07 s. v224's copy took 0.18 s. A full
initSchemafrom 222 to 224 took 9 s.Measured and not shipped
SET STORAGE MAINoncontent_chunks.embedding. At 5k it makes the joined plans pick HNSW in every stats state, but it's a net loss.SET embedding = embeddingkeeps the TOAST pointer, so it has to besubvector(). At 50k that took 629 s plus a 146 s VACUUM, wrote 7.7 GB of WAL with 0 HOT updates, and left the TOAST space stranded.ef_searchsizing. Any ef below 2× the window loses recall at both scales. Cutting only the walk LIMIT to 1.25–1.5× keeps recall and saves 3–7 ms at 50k, but hidden-row tolerance drops from 50% to 20–33%, and the remote-reader fixture would fall back.Tests
test/page-retrievals.test.tsruns the legacy UPDATE and the upsert over the same pages and ages:test/sync-movement.test.tschecks the watermark read gives identical results with and without index scans, across non-sync kinds, another incarnation, queued requests and compaction.test/serve-loop-migrations.test.tsandtest/e2e/serve-loop-migrations-postgres.test.tscheck a fresh install and an upgrade from 222: index swap, every timestamp copied, column untouched, idempotent re-run.test/e2e/persistence-consumers-postgres.test.tschecks the watermark plan uses the new index.test/search/vector-statement.test.ts,vector-index-walk.test.tsand the vector-plan E2E check that a small scope skips the walk and returns the joined rows, and that large scopes still walk. A forced probe with threshold 0 makes all three fail.