github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/ordering/ordering.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package ordering
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    15  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    16  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
    18  	"github.com/cockroachdb/cockroach/pkg/util"
    19  	"github.com/cockroachdb/cockroach/pkg/util/log"
    20  	"github.com/cockroachdb/errors"
    21  )
    22  
    23  // CanProvide returns true if the given operator returns rows that can
    24  // satisfy the given required ordering.
    25  func CanProvide(expr memo.RelExpr, required *physical.OrderingChoice) bool {
    26  	if required.Any() {
    27  		return true
    28  	}
    29  	if util.RaceEnabled {
    30  		checkRequired(expr, required)
    31  	}
    32  	return funcMap[expr.Op()].canProvideOrdering(expr, required)
    33  }
    34  
    35  // BuildChildRequired returns the ordering that must be required of its
    36  // given child in order to satisfy a required ordering. Can only be called if
    37  // CanProvide is true for the required ordering.
    38  func BuildChildRequired(
    39  	parent memo.RelExpr, required *physical.OrderingChoice, childIdx int,
    40  ) physical.OrderingChoice {
    41  	result := funcMap[parent.Op()].buildChildReqOrdering(parent, required, childIdx)
    42  	if util.RaceEnabled && !result.Any() {
    43  		checkRequired(parent.Child(childIdx).(memo.RelExpr), &result)
    44  	}
    45  	return result
    46  }
    47  
    48  // BuildProvided returns a specific ordering that the operator provides (and which
    49  // must be maintained on the results during distributed execution).
    50  //
    51  // The returned ordering, in conjunction with the operator's functional
    52  // dependencies, must intersect the required ordering.
    53  //
    54  // A best-effort attempt is made to make the provided orderings as simple as
    55  // possible (while still satisfying the required ordering).
    56  //
    57  // For example, if we scan an index on x,y,z with required ordering "+y opt(x)",
    58  // the provided ordering is "+x,+y". If we scan the same index with constraint
    59  // x=1, the provided ordering is "+y".
    60  //
    61  // This function assumes that the provided orderings have already been set in
    62  // the children of the expression.
    63  func BuildProvided(expr memo.RelExpr, required *physical.OrderingChoice) opt.Ordering {
    64  	if required.Any() {
    65  		return nil
    66  	}
    67  	provided := funcMap[expr.Op()].buildProvidedOrdering(expr, required)
    68  
    69  	if util.RaceEnabled {
    70  		checkProvided(expr, required, provided)
    71  	}
    72  
    73  	return provided
    74  }
    75  
    76  type funcs struct {
    77  	canProvideOrdering func(expr memo.RelExpr, required *physical.OrderingChoice) bool
    78  
    79  	buildChildReqOrdering func(
    80  		parent memo.RelExpr, required *physical.OrderingChoice, childIdx int,
    81  	) physical.OrderingChoice
    82  
    83  	buildProvidedOrdering func(
    84  		expr memo.RelExpr, required *physical.OrderingChoice,
    85  	) opt.Ordering
    86  }
    87  
    88  var funcMap [opt.NumOperators]funcs
    89  
    90  func init() {
    91  	for _, op := range opt.RelationalOperators {
    92  		funcMap[op] = funcs{
    93  			canProvideOrdering:    canNeverProvideOrdering,
    94  			buildChildReqOrdering: noChildReqOrdering,
    95  			buildProvidedOrdering: noProvidedOrdering,
    96  		}
    97  	}
    98  	funcMap[opt.ScanOp] = funcs{
    99  		canProvideOrdering:    scanCanProvideOrdering,
   100  		buildChildReqOrdering: noChildReqOrdering,
   101  		buildProvidedOrdering: scanBuildProvided,
   102  	}
   103  	funcMap[opt.SelectOp] = funcs{
   104  		canProvideOrdering:    selectCanProvideOrdering,
   105  		buildChildReqOrdering: selectBuildChildReqOrdering,
   106  		buildProvidedOrdering: selectBuildProvided,
   107  	}
   108  	funcMap[opt.ProjectOp] = funcs{
   109  		canProvideOrdering:    projectCanProvideOrdering,
   110  		buildChildReqOrdering: projectBuildChildReqOrdering,
   111  		buildProvidedOrdering: projectBuildProvided,
   112  	}
   113  	funcMap[opt.IndexJoinOp] = funcs{
   114  		canProvideOrdering:    lookupOrIndexJoinCanProvideOrdering,
   115  		buildChildReqOrdering: lookupOrIndexJoinBuildChildReqOrdering,
   116  		buildProvidedOrdering: indexJoinBuildProvided,
   117  	}
   118  	funcMap[opt.LookupJoinOp] = funcs{
   119  		canProvideOrdering:    lookupOrIndexJoinCanProvideOrdering,
   120  		buildChildReqOrdering: lookupOrIndexJoinBuildChildReqOrdering,
   121  		buildProvidedOrdering: lookupJoinBuildProvided,
   122  	}
   123  	funcMap[opt.OrdinalityOp] = funcs{
   124  		canProvideOrdering:    ordinalityCanProvideOrdering,
   125  		buildChildReqOrdering: ordinalityBuildChildReqOrdering,
   126  		buildProvidedOrdering: ordinalityBuildProvided,
   127  	}
   128  	funcMap[opt.MergeJoinOp] = funcs{
   129  		canProvideOrdering:    mergeJoinCanProvideOrdering,
   130  		buildChildReqOrdering: mergeJoinBuildChildReqOrdering,
   131  		buildProvidedOrdering: mergeJoinBuildProvided,
   132  	}
   133  	funcMap[opt.LimitOp] = funcs{
   134  		canProvideOrdering:    limitOrOffsetCanProvideOrdering,
   135  		buildChildReqOrdering: limitOrOffsetBuildChildReqOrdering,
   136  		buildProvidedOrdering: limitOrOffsetBuildProvided,
   137  	}
   138  	funcMap[opt.OffsetOp] = funcs{
   139  		canProvideOrdering:    limitOrOffsetCanProvideOrdering,
   140  		buildChildReqOrdering: limitOrOffsetBuildChildReqOrdering,
   141  		buildProvidedOrdering: limitOrOffsetBuildProvided,
   142  	}
   143  	funcMap[opt.ScalarGroupByOp] = funcs{
   144  		// ScalarGroupBy always has exactly one result; any required ordering should
   145  		// have been simplified to Any (unless normalization rules are disabled).
   146  		canProvideOrdering:    canNeverProvideOrdering,
   147  		buildChildReqOrdering: scalarGroupByBuildChildReqOrdering,
   148  		buildProvidedOrdering: noProvidedOrdering,
   149  	}
   150  	funcMap[opt.GroupByOp] = funcs{
   151  		canProvideOrdering:    groupByCanProvideOrdering,
   152  		buildChildReqOrdering: groupByBuildChildReqOrdering,
   153  		buildProvidedOrdering: groupByBuildProvided,
   154  	}
   155  	funcMap[opt.DistinctOnOp] = funcs{
   156  		canProvideOrdering:    distinctOnCanProvideOrdering,
   157  		buildChildReqOrdering: distinctOnBuildChildReqOrdering,
   158  		buildProvidedOrdering: distinctOnBuildProvided,
   159  	}
   160  	funcMap[opt.EnsureDistinctOnOp] = funcs{
   161  		canProvideOrdering:    distinctOnCanProvideOrdering,
   162  		buildChildReqOrdering: distinctOnBuildChildReqOrdering,
   163  		buildProvidedOrdering: distinctOnBuildProvided,
   164  	}
   165  	funcMap[opt.UpsertDistinctOnOp] = funcs{
   166  		canProvideOrdering:    distinctOnCanProvideOrdering,
   167  		buildChildReqOrdering: distinctOnBuildChildReqOrdering,
   168  		buildProvidedOrdering: distinctOnBuildProvided,
   169  	}
   170  	funcMap[opt.EnsureUpsertDistinctOnOp] = funcs{
   171  		canProvideOrdering:    distinctOnCanProvideOrdering,
   172  		buildChildReqOrdering: distinctOnBuildChildReqOrdering,
   173  		buildProvidedOrdering: distinctOnBuildProvided,
   174  	}
   175  	funcMap[opt.SortOp] = funcs{
   176  		canProvideOrdering:    nil, // should never get called
   177  		buildChildReqOrdering: sortBuildChildReqOrdering,
   178  		buildProvidedOrdering: sortBuildProvided,
   179  	}
   180  	funcMap[opt.InsertOp] = funcs{
   181  		canProvideOrdering:    mutationCanProvideOrdering,
   182  		buildChildReqOrdering: mutationBuildChildReqOrdering,
   183  		buildProvidedOrdering: mutationBuildProvided,
   184  	}
   185  	funcMap[opt.UpdateOp] = funcs{
   186  		canProvideOrdering:    mutationCanProvideOrdering,
   187  		buildChildReqOrdering: mutationBuildChildReqOrdering,
   188  		buildProvidedOrdering: mutationBuildProvided,
   189  	}
   190  	funcMap[opt.UpsertOp] = funcs{
   191  		canProvideOrdering:    mutationCanProvideOrdering,
   192  		buildChildReqOrdering: mutationBuildChildReqOrdering,
   193  		buildProvidedOrdering: mutationBuildProvided,
   194  	}
   195  	funcMap[opt.DeleteOp] = funcs{
   196  		canProvideOrdering:    mutationCanProvideOrdering,
   197  		buildChildReqOrdering: mutationBuildChildReqOrdering,
   198  		buildProvidedOrdering: mutationBuildProvided,
   199  	}
   200  	funcMap[opt.ExplainOp] = funcs{
   201  		canProvideOrdering:    canNeverProvideOrdering,
   202  		buildChildReqOrdering: explainBuildChildReqOrdering,
   203  		buildProvidedOrdering: noProvidedOrdering,
   204  	}
   205  	funcMap[opt.AlterTableSplitOp] = funcs{
   206  		canProvideOrdering:    canNeverProvideOrdering,
   207  		buildChildReqOrdering: alterTableSplitBuildChildReqOrdering,
   208  		buildProvidedOrdering: noProvidedOrdering,
   209  	}
   210  	funcMap[opt.AlterTableUnsplitOp] = funcs{
   211  		canProvideOrdering:    canNeverProvideOrdering,
   212  		buildChildReqOrdering: alterTableUnsplitBuildChildReqOrdering,
   213  		buildProvidedOrdering: noProvidedOrdering,
   214  	}
   215  	funcMap[opt.AlterTableRelocateOp] = funcs{
   216  		canProvideOrdering:    canNeverProvideOrdering,
   217  		buildChildReqOrdering: alterTableRelocateBuildChildReqOrdering,
   218  		buildProvidedOrdering: noProvidedOrdering,
   219  	}
   220  	funcMap[opt.ControlJobsOp] = funcs{
   221  		canProvideOrdering:    canNeverProvideOrdering,
   222  		buildChildReqOrdering: controlJobsBuildChildReqOrdering,
   223  		buildProvidedOrdering: noProvidedOrdering,
   224  	}
   225  	funcMap[opt.CancelQueriesOp] = funcs{
   226  		canProvideOrdering:    canNeverProvideOrdering,
   227  		buildChildReqOrdering: cancelQueriesBuildChildReqOrdering,
   228  		buildProvidedOrdering: noProvidedOrdering,
   229  	}
   230  	funcMap[opt.CancelSessionsOp] = funcs{
   231  		canProvideOrdering:    canNeverProvideOrdering,
   232  		buildChildReqOrdering: cancelSessionsBuildChildReqOrdering,
   233  		buildProvidedOrdering: noProvidedOrdering,
   234  	}
   235  	funcMap[opt.ExportOp] = funcs{
   236  		canProvideOrdering:    canNeverProvideOrdering,
   237  		buildChildReqOrdering: exportBuildChildReqOrdering,
   238  		buildProvidedOrdering: noProvidedOrdering,
   239  	}
   240  }
   241  
   242  func canNeverProvideOrdering(expr memo.RelExpr, required *physical.OrderingChoice) bool {
   243  	return false
   244  }
   245  
   246  func noChildReqOrdering(
   247  	parent memo.RelExpr, required *physical.OrderingChoice, childIdx int,
   248  ) physical.OrderingChoice {
   249  	return physical.OrderingChoice{}
   250  }
   251  
   252  func noProvidedOrdering(expr memo.RelExpr, required *physical.OrderingChoice) opt.Ordering {
   253  	return nil
   254  }
   255  
   256  // remapProvided remaps columns in a provided ordering (according to the given
   257  // FDs) so that it only refers to columns in the given outCols set. It also
   258  // removes any columns that are redundant according to the FDs.
   259  //
   260  // Can only be called if the provided ordering can be remapped.
   261  //
   262  // Does not modify <provided> in place, but it can return the same slice.
   263  func remapProvided(provided opt.Ordering, fds *props.FuncDepSet, outCols opt.ColSet) opt.Ordering {
   264  	if len(provided) == 0 {
   265  		return nil
   266  	}
   267  
   268  	// result is nil until we determine that we need to make a copy.
   269  	var result opt.Ordering
   270  
   271  	// closure is the set of columns that are functionally determined by the
   272  	// columns in provided[:i].
   273  	closure := fds.ComputeClosure(opt.ColSet{})
   274  	for i := range provided {
   275  		col := provided[i].ID()
   276  		if closure.Contains(col) {
   277  			// At the level of the new operator, this column is redundant.
   278  			if result == nil {
   279  				result = make(opt.Ordering, i, len(provided))
   280  				copy(result, provided)
   281  			}
   282  			continue
   283  		}
   284  		if outCols.Contains(col) {
   285  			if result != nil {
   286  				result = append(result, provided[i])
   287  			}
   288  		} else {
   289  			equivCols := fds.ComputeEquivClosure(opt.MakeColSet(col))
   290  			remappedCol, ok := equivCols.Intersection(outCols).Next(0)
   291  			if !ok {
   292  				panic(errors.AssertionFailedf("no output column equivalent to %d", log.Safe(col)))
   293  			}
   294  			if result == nil {
   295  				result = make(opt.Ordering, i, len(provided))
   296  				copy(result, provided)
   297  			}
   298  			result = append(result, opt.MakeOrderingColumn(
   299  				remappedCol, provided[i].Descending(),
   300  			))
   301  		}
   302  		closure.Add(col)
   303  		closure = fds.ComputeClosure(closure)
   304  	}
   305  	if result == nil {
   306  		return provided
   307  	}
   308  	return result
   309  }
   310  
   311  // trimProvided returns the smallest prefix of <provided> that is sufficient to
   312  // satisfy <required> (in conjunction with the FDs).
   313  //
   314  // This is useful because in a distributed setting execution is configured to
   315  // maintain the provided ordering when merging results from multiple nodes, and
   316  // we don't want to make needless comparisons.
   317  func trimProvided(
   318  	provided opt.Ordering, required *physical.OrderingChoice, fds *props.FuncDepSet,
   319  ) opt.Ordering {
   320  	if len(provided) == 0 {
   321  		return nil
   322  	}
   323  	// closure is the set of columns that are functionally determined by the
   324  	// columns in provided[:provIdx].
   325  	closure := fds.ComputeClosure(opt.ColSet{})
   326  	provIdx := 0
   327  	for reqIdx := range required.Columns {
   328  		c := &required.Columns[reqIdx]
   329  		// Consume columns from the provided ordering until their closure intersects
   330  		// the required group.
   331  		for !closure.Intersects(c.Group) {
   332  			closure.Add(provided[provIdx].ID())
   333  			closure = fds.ComputeClosure(closure)
   334  			provIdx++
   335  			if provIdx == len(provided) {
   336  				return provided
   337  			}
   338  		}
   339  	}
   340  	return provided[:provIdx]
   341  }
   342  
   343  // checkRequired runs sanity checks on the ordering required of an operator.
   344  func checkRequired(expr memo.RelExpr, required *physical.OrderingChoice) {
   345  	rel := expr.Relational()
   346  
   347  	// Verify that the ordering only refers to output columns.
   348  	if !required.SubsetOfCols(rel.OutputCols) {
   349  		panic(errors.AssertionFailedf("required ordering refers to non-output columns (op %s)", log.Safe(expr.Op())))
   350  	}
   351  
   352  	// Verify that columns in a column group are equivalent.
   353  	for i := range required.Columns {
   354  		c := &required.Columns[i]
   355  		if !c.Group.SubsetOf(rel.FuncDeps.ComputeEquivGroup(c.AnyID())) {
   356  			panic(errors.AssertionFailedf(
   357  				"ordering column group %s contains non-equivalent columns (op %s)",
   358  				c.Group, expr.Op(),
   359  			))
   360  		}
   361  	}
   362  }
   363  
   364  // checkProvided runs sanity checks on a provided ordering.
   365  func checkProvided(expr memo.RelExpr, required *physical.OrderingChoice, provided opt.Ordering) {
   366  	// The provided ordering must refer only to output columns.
   367  	if outCols := expr.Relational().OutputCols; !provided.ColSet().SubsetOf(outCols) {
   368  		panic(errors.AssertionFailedf(
   369  			"provided %s must refer only to output columns %s", provided, outCols,
   370  		))
   371  	}
   372  
   373  	// TODO(radu): this check would be nice to have, but it is too strict. In some
   374  	// cases, child expressions created during exploration (like constrained
   375  	// scans) have FDs that are more restricted than what was known when the
   376  	// parent expression was constructed. Related to #32320.
   377  	if false {
   378  		// The provided ordering must intersect the required ordering, after FDs are
   379  		// applied.
   380  		fds := &expr.Relational().FuncDeps
   381  		r := required.Copy()
   382  		r.Simplify(fds)
   383  		var p physical.OrderingChoice
   384  		p.FromOrdering(provided)
   385  		p.Simplify(fds)
   386  		if !r.Any() && (p.Any() || !p.Intersects(&r)) {
   387  			panic(errors.AssertionFailedf(
   388  				"provided %s does not intersect required %s (FDs: %s)", provided, required, fds,
   389  			))
   390  		}
   391  	}
   392  
   393  	// The provided ordering should not have unnecessary columns.
   394  	fds := &expr.Relational().FuncDeps
   395  	if trimmed := trimProvided(provided, required, fds); len(trimmed) != len(provided) {
   396  		panic(errors.AssertionFailedf(
   397  			"provided %s can be trimmed to %s (FDs: %s)", log.Safe(provided), log.Safe(trimmed), log.Safe(fds),
   398  		))
   399  	}
   400  }