Skip to content

Intersect index ranges and union disjunctions in the planner - #26

Merged
venkat1701 merged 3 commits into
mainfrom
feat/planner-index-intersection
Oct 4, 2026
Merged

venkat1701 merged 3 commits into
mainfrom
feat/planner-index-intersection

Conversation

@venkat1701

Copy link
Copy Markdown
Collaborator

Closes #12

The planner picked one access path per MATCH and checked everything else row by row. It now has two composite paths:

  • Intersection (AND): conjuncts whose path is exact for them (index ranges, JSON-path ranges, CONTAINS, IN, an atom equality) are sorted by estimated rows, and every prefix of two to four becomes a candidate. Each part is scanned into a sorted id array and merge-intersected. Rows are estimated as rows1 * product(rows_i / population). Cost is the sum of the part scans plus verifying whatever wasn't consumed.
  • Union (OR): if every operand of a disjunction has its own path, the parts are scanned and merged. When each part is exact, the whole OR is consumed and not verified again.

Candidates now carry the list of conjuncts they consume, rather than a single optional source, so the residual filter is just the conjuncts nobody consumed.

The cost model is unchanged, which means intersection only wins when it actually should. Scanning a second index costs about as much per row as verifying a row, plus a fixed per-scan overhead, so on small data a single selective index still wins. That's why the test builds 4,000 items: two colours and two shapes split evenly, so each predicate matches 2,000 rows and the pair matches 1,000.

broadPredicatesAreIntersectedAndDisjunctionsUnioned in QueryLanguageTest checks:

  • The plans: Intersect[...] for the AND, and Union[...] with no Verify step for the OR.
  • The counts against a version of the same query the planner can't index.

Full ./mvnw install passes locally and every commit compiles on its own.

The planner used a single access path per MATCH. It now also costs
intersections over the cheapest exact paths for AND, and a union when every
operand of an OR has its own path. Candidates carry the conjuncts they
consume, so only the rest are verified row by row.
@venkat1701
venkat1701 force-pushed the feat/planner-index-intersection branch from 859c6d0 to 04bf764 Compare October 4, 2026 08:25
@venkat1701
venkat1701 merged commit 0c0f9b2 into main Oct 4, 2026
@venkat1701
venkat1701 deleted the feat/planner-index-intersection branch October 6, 2026 00:54
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.

Planner uses one access path per MATCH

1 participant