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 }