fix(planner): credit unindexed equality filters in start-point selection - #209
Merged
Conversation
An unindexed literal-equality conjunct made its endpoint price *worse*
in plan_reversed_pattern's model: it left the row estimate at the full
label count and set `filtered`, doubling the scan term with no
selectivity credit. On the LDBC-style SF 0.1 workload without indexes,
`MATCH (m:Post {id: 100})-[:HAS_CREATOR]->(p:Person)` anchored at
Person and walked all 15k HAS_CREATOR edges (33.9ms vs 5.6ms for the
same scan without the hop), and a variant with an unlabeled far
endpoint anchored an AllNodesScan (650ms). Issue #208 has the full
pricing arithmetic.
Split EndpointCost's single `rows` into `scan_rows` (physical: index
count for a seek, else the full label — an unindexed filter never
shrinks the scan) and `out_rows` (emitted into the Expand: exact for a
seek; an unindexed literal equality now gets System R's classic 1/10
default selectivity, UNINDEXED_EQ_SELECTIVITY_DIVISOR). The scan term
prices scan_rows, the edge-walk proration uses out_rows. Keeping the
scan term full is what preserves the cases the old model got right: a
low-selectivity equality against a tiny far endpoint still reverses,
and the CONTAINS shape from the model's original motivating benchmark
is untouched (non-equality filters keep selectivity 1 — genuinely
unknowable).
Measured after (same workload, no indexes): 33.9ms -> 5.58ms (6.1x, now
at parity with the hop-less twin) and 650ms -> 9.6ms (68x, equal to its
indexed time). All other suite rows unchanged within noise.
TCK: 3880/3880, unchanged. Fixes #208.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…h section The table's indexed numbers are unaffected by #209 (verified against criterion baselines); record the unindexed before/after where the workload's numbers live.
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.
Fixes #208 — see the issue for the measured symptom and the full pricing arithmetic.
What
EndpointCost's singlerowssplits into:scan_rows— what the leaf physically visits: the index-match count when a seek fuses, else the full label count (an unindexed filter never shrinks a scan);out_rows— what the leaf emits into the Expand: exact for a seek; an unindexed literal equality now gets a default 1/10 selectivity (UNINDEXED_EQ_SELECTIVITY_DIVISOR, System R's classic no-statistics default).anchor_costprices the scan term withscan_rows(+ the per-row filter multiplier as before) and prorates the edge walk without_rows. Keeping the scan term full is what preserves the old model's correct cases: a low-selectivity equality against a tiny far endpoint still reverses, and theCONTAINSshape from the model's original motivating benchmark is untouched (non-equality filters keep selectivity 1).Measured (LDBC-style SF 0.1, no indexes)
Verification
cargo test --workspacegreen; SF 0.1--ignoredworkload test green; TCK 3880/3880 unchanged; fmt + both clippy configs clean