perf(postgres): avoid repeated parameter rescans - #1431
Open
Gordex2014 wants to merge 1 commit into
Open
Gordex2014 wants to merge 1 commit into
Gordex2014 wants to merge 1 commit into
Conversation
Gordex2014
marked this pull request as ready for review
September 21, 2026 21:00
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
Closes #1416.
Summary
INTERSECT.Why this fixes the reported plan
The previous SQL emitted one
id IN (SELECT ...)condition per occurrence. PostgreSQL could plan the pair as nested semi-joins and rerun one date scan once per candidate from the other arm.The new SQL intersects the occurrences' resource-id sets inside one membership test. Different indexed values on a multi-valued date can still satisfy different occurrences, so this preserves resource-level semantics without merging predicates onto one index row.
Evidence
The deterministic PostgreSQL 16 benchmark reproduced the nested-loop rescan at two sizes. On the 24k-Patient scale, the page changed from 33.4 s and 7.42 million buffers to 21.3 ms and 15,360 buffers. The count changed from 33.8 s to 18.6 ms. Every
INTERSECTarm executed once, returned pages and counts matched the seed-derived expected results, and no capture spilled at 10 MB or 64 kBwork_mem.When the corpus doubled, page buffers grew by 3.915x before and 1.999x after. The committed benchmark document records the method, controls, raw figures, and limitations. The CI plan script captures both the emitted shape and the previous two-membership control on the full benchmark database.
The original manual-QA corpus from #1416 was not rerun. The deterministic corpus reproduces the same rescanning mechanism and verifies its removal, but it does not replace a final confirmation of the reported 1,268-Patient result on that original data.
Compatibility
Encounter.periodcan satisfy separate occurrences with separate indexed values.search_count, both_totalmodes, cursor paging, offset paging, conditional criteria, and tenant isolation use the same result set.Checks
cargo fmt --all --checkhelios-persistencelibrary testscargo clippy -p helios-persistence --features postgres --all-targetswith no new warningsRisk
The measured gain applies to the misestimated nested-rescan regime reported in #1416. When both repeated arms match a very large share of a resource type, PostgreSQL 16 may prefer a parallel hash-semi-join plan for the old conjunction, while the
SetOpconsume/deduplicate step runs in one process. The benchmark documentation calls out this boundary and the plan script includes the old and new shapes for comparison.Visual explanation
Open the interactive explanation
Temporary review evidence expires
2026-09-26T20:55:20.497Z.