// Sort-limit fusion: a trailing segment that only orders, paginates, and // re-projects the previous segment's columns forces that segment to // materialize every row it produces, even though at most skip+limit can // ever surface. Donating the ORDER BY / OFFSET / LIMIT upstream lets the // producing segment's bounded sink retain skip+limit rows and refuse the // rest before they are built (the NEXT-authored ORDER BY form of the // LDBC IC queries). The donor keeps its projection, now over the already // ordered, already truncated rows.
package plan import // DisableSortLimitFusion pins result identity in tests: the unfused // pipeline must produce exactly the rows the fused one does, in the // same order. var DisableSortLimitFusion bool // fuseSortLimit hoists each qualifying segment's ordering and pagination // into its producer, scanning producers first so an aligned chain can // cascade. The donor must be a pure projection (no stages, no // post-where, not distinct, not aggregated) whose ORDER BY keys are bare // references to the producer's output columns and whose LIMIT bounds the // retention; the receiver must not order, paginate, or post-filter on // its own (a receiver post-where runs before the donor's sort-limit in // the unfused pipeline, so hoisting past it would reorder semantics). func fuseSortLimit( []*Segment) { if DisableSortLimitFusion { return } for := len() - 2; >= 0; -- { , := [], [+1] if !sortLimitDonor() || !sortLimitReceiver() { continue } if !orderKeysAreColumns(.Proj.OrderBy, &.Proj) { continue } .Proj.OrderBy = .Proj.OrderBy .Proj.Skip = .Proj.Skip .Proj.Limit = .Proj.Limit .Proj.OrderBy = nil .Proj.Skip = nil .Proj.Limit = nil } } // sortLimitDonor: a stage-less, filter-less, non-distinct, // non-aggregated projection segment carrying both an ORDER BY and a // LIMIT (a bound; ORDER BY alone retains everything and buys nothing). func sortLimitDonor( *Segment) bool { return len(.Stages) == 0 && .PostWhere == nil && !.Proj.Distinct && !.Proj.Aggregated && len(.Proj.Post) == 0 && .Proj.NHidden == 0 && len(.Proj.OrderBy) > 0 && .Proj.Limit != nil } // sortLimitReceiver: no ordering or pagination of its own to compete // with the donated one, and no post-where the donation would leapfrog. func sortLimitReceiver( *Segment) bool { return len(.Proj.OrderBy) == 0 && .Proj.Limit == nil && .Proj.Skip == nil && .PostWhere == nil } // orderKeysAreColumns reports whether every sort key is a bare variable // naming one of the receiver's output columns -- the only form whose // meaning is unchanged by evaluation in the receiver's scope (an // arbitrary expression could collide with a receiver match variable of // the same name). func orderKeysAreColumns( []ast.SortItem, *ProjPlan) bool { for := range { , := [].Expr.(*ast.Var) if ! { return false } := false for , := range .Columns { if == .Name { = true break } } if ! { return false } } return true }