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 }