Conversation
Q6 regressed 722ms -> 1064ms after degree-stats fan-out costing: the last MATCH (UNNEST_CORRELATED leg over f, post, t, tag with t.ID = knownTagId pulled above the join) flipped from tag-seeded BWD chains to a full 1M-Post scan with FWD extends plus two tag-attach hash joins (2.76M rows at ~300ms extra), because honest fan-out put both candidates in the same league and the full-plan comparison tipped the wrong way. Plan the leg from the seed value instead (tryPlanScalarSeededChain): PK lookup of the seed node keyed by the outer scalar, tree-walk extends covering every rel (outer-bound neighbors via fresh variable copies), deferred residual filters, property-attach joins. Fires only for single-graph, non-recursive legs with exactly one convertible PK equality whose key is outer-evaluable with an outer dependent, full acyclic coverage, and filter-placeable residuals; anything else falls back untouched. Two execution hazards handled: - An independent key subplan (deep copy of the outer prefix, audited operator types only) computes the chain once per DISTINCT key and hash-joins back, instead of repeating the walk per outer row (8263 x 863-post fan-out). - Probe-to-build SIP prohibited on the new joins: the build recomputes the probe's own values, so masks prune nothing while materializing wide probe rows (140MB friends-list round-trip). Measured on LDBC SNB SF1 (lbug shell): Q6 1064ms -> ~140ms with identical results (also beats the 747ms pre-regression baseline); Q5/Q7/Q10/Q12/Q14 unchanged (Q7 blip verified as noise vs baseline binary).
…#935) Classify every LogicalOperatorType enumerator explicitly (18 audited true, 44 conservative false) instead of default:false, so -Wswitch fails the build on unclassified new operators. A trailing return false guards only out-of-range values and does not silence the warning (verified: removing one case produces 'enumeration value not handled in switch', fatal under ENABLE_WERROR=ON). No behavior change.
Contributor
Author
Q6 plan change (before → after),
|
| Before | After | Why faster |
|---|---|---|
SCAN Post (1M) → 2× FWD extend → 2 tag hash joins |
PK_LOOKUP Tag BY knownTagId → 1 tag |
Seed instead of scan; the t.ID=knownTagId filter disappears (consumed as the seed) |
Tag side blows up to 3.4M (post,tag) rows |
863 posts → 2992 (post,tag) pairs → 181 creators, computed once |
DISTINCT-key subplan + pair join removes the 8263× per-row duplication |
f via full Person scan inside the 2.76M-row build |
post→_0__22_f (fresh copy; the binder rebinds f per scope, so correlation is matched at _22_f._ID level) joined back on (f,fresh)+(key,key) |
Correlation without re-scan; extending into the bound f would collide scopes since physical extend overwrites |
3× ACCUMULATE barriers (probe-side materialization of wide rows incl. 8263-int friends lists, ~800ms) |
none on the new joins (PROHIBIT_PROBE_TO_BUILD; the build recomputes probe's own values so masks prune nothing) |
Single biggest time drop |
tag.name via 2 hash joins over millions of rows |
one attach join, probe = 2063 joined rows, build = masked Tag scan | Attach happens after the fan-in, not during |
Net: 2,763,342-row build → ~5k-row chain + 2063-row join output (same 2063 → 1520 groups → top-10).
Repro query (Q6, SF1 params inline)
MATCH (knownTag:Tag {name: 'Carl_Gustaf_Emil_Mannerheim'})
WITH knownTag.ID AS knownTagId
MATCH (person:Person {ID: 2199023262543})-[:knows*1..2]-(friend:Person)
WHERE NOT person = friend
WITH knownTagId, COLLECT(DISTINCT friend) AS friends
UNWIND friends AS f
MATCH (f)<-[:postHasCreator]-(post:Post),
(post)-[:postHasTag]->(t:Tag {ID: knownTagId}),
(post)-[:postHasTag]->(tag:Tag)
WHERE NOT t = tag
WITH tag.name AS tagName, COUNT(post) AS postCount
RETURN tagName, postCount
ORDER BY postCount DESC, tagName ASC
LIMIT 10;Dump via LBUG_DUMP_LOGICAL=1 lbug ldbc_snb_sf1.lbdb -r (pre-PR binary shows the "before" shape above).
This branch has not been deployed
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.
Q6 regressed 722ms -> 1064ms after degree-stats fan-out costing (#1046): the last MATCH (UNNEST_CORRELATED leg over f, post, t, tag with
t.ID = knownTagIdpulled above the join) flipped from tag-seeded BWD chains to a full 1M-Post scan with FWD extends plus two tag-attach hash joins, because honest fan-out put both candidates in the same league and the full-plan comparison tipped the wrong way (same 2.76M rows, ~300ms more expensive route).Changes (
plan_subquery.cpp,planner.h)New
tryPlanScalarSeededChain, called fromplanRegularMatchafter the collect-membership unnest (mutually exclusive triggers). Plans the leg from the seed value directly:f._ID=f._IDtautology must wait for the joined scope); property-attach joins for unfetched leg-node properties.Strict bail-outs throughout (single graph, non-recursive rels, single convertible equality with outer-var key, no LIST_CONTAINS, acyclic full coverage, filter-placeable residuals) fall back to regular planning untouched.
Measurements (LDBC SNB SF1,
lbugshell)clang-format clean. Full e2e left to CI.