github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/xform/interesting_orderings.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 xform
    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  )
    19  
    20  // DeriveInterestingOrderings calculates and returns the
    21  // Relational.Rule.InterestingOrderings property of a relational operator.
    22  func DeriveInterestingOrderings(e memo.RelExpr) opt.OrderingSet {
    23  	l := e.Relational()
    24  	if l.IsAvailable(props.InterestingOrderings) {
    25  		return l.Rule.InterestingOrderings
    26  	}
    27  	l.SetAvailable(props.InterestingOrderings)
    28  
    29  	var res opt.OrderingSet
    30  	switch e.Op() {
    31  	case opt.ScanOp:
    32  		res = interestingOrderingsForScan(e.(*memo.ScanExpr))
    33  
    34  	case opt.SelectOp, opt.IndexJoinOp, opt.LookupJoinOp:
    35  		// Pass through child orderings.
    36  		res = DeriveInterestingOrderings(e.Child(0).(memo.RelExpr))
    37  
    38  	case opt.ProjectOp:
    39  		res = interestingOrderingsForProject(e.(*memo.ProjectExpr))
    40  
    41  	case opt.GroupByOp, opt.ScalarGroupByOp:
    42  		res = interestingOrderingsForGroupBy(e)
    43  
    44  	case opt.LimitOp, opt.OffsetOp:
    45  		res = interestingOrderingsForLimit(e)
    46  
    47  	default:
    48  		if opt.IsJoinOp(e) {
    49  			res = interestingOrderingsForJoin(e)
    50  			break
    51  		}
    52  
    53  		res = opt.OrderingSet{}
    54  	}
    55  
    56  	l.Rule.InterestingOrderings = res
    57  	return res
    58  }
    59  
    60  func interestingOrderingsForScan(scan *memo.ScanExpr) opt.OrderingSet {
    61  	md := scan.Memo().Metadata()
    62  	tab := md.Table(scan.Table)
    63  	ord := make(opt.OrderingSet, 0, tab.IndexCount())
    64  	for i := 0; i < tab.IndexCount(); i++ {
    65  		index := tab.Index(i)
    66  		if index.IsInverted() {
    67  			continue
    68  		}
    69  		numIndexCols := index.KeyColumnCount()
    70  		var o opt.Ordering
    71  		for j := 0; j < numIndexCols; j++ {
    72  			indexCol := index.Column(j)
    73  			colID := scan.Table.ColumnID(indexCol.Ordinal)
    74  			if !scan.Cols.Contains(colID) {
    75  				break
    76  			}
    77  			if o == nil {
    78  				o = make(opt.Ordering, 0, numIndexCols)
    79  			}
    80  			o = append(o, opt.MakeOrderingColumn(colID, indexCol.Descending))
    81  		}
    82  		if o != nil {
    83  			ord.Add(o)
    84  		}
    85  	}
    86  	return ord
    87  }
    88  
    89  func interestingOrderingsForProject(prj *memo.ProjectExpr) opt.OrderingSet {
    90  	inOrd := DeriveInterestingOrderings(prj.Input)
    91  	res := inOrd.Copy()
    92  	res.RestrictToCols(prj.Passthrough)
    93  	return res
    94  }
    95  
    96  func interestingOrderingsForGroupBy(rel memo.RelExpr) opt.OrderingSet {
    97  	private := rel.Private().(*memo.GroupingPrivate)
    98  	if private.GroupingCols.Empty() {
    99  		// This is a scalar group-by, returning a single row.
   100  		return nil
   101  	}
   102  
   103  	res := DeriveInterestingOrderings(rel.Child(0).(memo.RelExpr)).Copy()
   104  	if !private.Ordering.Any() {
   105  		ordering := private.Ordering.ToOrdering()
   106  		res.RestrictToPrefix(ordering)
   107  		if len(res) == 0 {
   108  			res.Add(ordering)
   109  		}
   110  	}
   111  
   112  	// We can only keep orderings on grouping columns.
   113  	res.RestrictToCols(private.GroupingCols)
   114  	return res
   115  }
   116  
   117  func interestingOrderingsForLimit(rel memo.RelExpr) opt.OrderingSet {
   118  	res := DeriveInterestingOrderings(rel.Child(0).(memo.RelExpr))
   119  	ord := rel.Private().(*physical.OrderingChoice).ToOrdering()
   120  	if ord.Empty() {
   121  		return res
   122  	}
   123  	res = res.Copy()
   124  	res.RestrictToPrefix(ord)
   125  	if len(res) == 0 {
   126  		res.Add(ord)
   127  	}
   128  	return res
   129  }
   130  
   131  func interestingOrderingsForJoin(rel memo.RelExpr) opt.OrderingSet {
   132  	if rel.Op() == opt.SemiJoinOp || rel.Op() == opt.AntiJoinOp {
   133  		// TODO(radu): perhaps take into account right-side interesting orderings on
   134  		// equality columns.
   135  		return DeriveInterestingOrderings(rel.Child(0).(memo.RelExpr))
   136  	}
   137  	// For a join, we could conceivably preserve the order of one side (even with
   138  	// hash-join, depending on which side we store).
   139  	ordLeft := DeriveInterestingOrderings(rel.Child(0).(memo.RelExpr))
   140  	ordRight := DeriveInterestingOrderings(rel.Child(1).(memo.RelExpr))
   141  	ord := make(opt.OrderingSet, 0, len(ordLeft)+len(ordRight))
   142  	ord = append(ord, ordLeft...)
   143  	ord = append(ord, ordRight...)
   144  	return ord
   145  }