You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
3.1 KiB
86 lines
3.1 KiB
// Copyright 2018 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package cascades
|
|
|
|
import (
|
|
"math"
|
|
|
|
plannercore "github.com/pingcap/tidb/planner/core"
|
|
"github.com/pingcap/tidb/planner/implementation"
|
|
"github.com/pingcap/tidb/planner/memo"
|
|
"github.com/pingcap/tidb/planner/property"
|
|
"github.com/pingcap/tidb/planner/util"
|
|
)
|
|
|
|
// Enforcer defines the interface for enforcer rules.
|
|
type Enforcer interface {
|
|
// NewProperty generates relaxed property with the help of enforcer.
|
|
NewProperty(prop *property.PhysicalProperty) (newProp *property.PhysicalProperty)
|
|
// OnEnforce adds physical operators on top of child implementation to satisfy
|
|
// required physical property.
|
|
OnEnforce(reqProp *property.PhysicalProperty, child memo.Implementation) (impl memo.Implementation)
|
|
// GetEnforceCost calculates cost of enforcing required physical property.
|
|
GetEnforceCost(g *memo.Group) float64
|
|
}
|
|
|
|
// GetEnforcerRules gets all candidate enforcer rules based
|
|
// on required physical property.
|
|
func GetEnforcerRules(g *memo.Group, prop *property.PhysicalProperty) (enforcers []Enforcer) {
|
|
if g.EngineType != memo.EngineTiDB {
|
|
return
|
|
}
|
|
if !prop.IsEmpty() {
|
|
enforcers = append(enforcers, orderEnforcer)
|
|
}
|
|
return
|
|
}
|
|
|
|
// OrderEnforcer enforces order property on child implementation.
|
|
type OrderEnforcer struct {
|
|
}
|
|
|
|
var orderEnforcer = &OrderEnforcer{}
|
|
|
|
// NewProperty removes order property from required physical property.
|
|
func (e *OrderEnforcer) NewProperty(prop *property.PhysicalProperty) (newProp *property.PhysicalProperty) {
|
|
// Order property cannot be empty now.
|
|
newProp = &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64}
|
|
return
|
|
}
|
|
|
|
// OnEnforce adds sort operator to satisfy required order property.
|
|
func (e *OrderEnforcer) OnEnforce(reqProp *property.PhysicalProperty, child memo.Implementation) (impl memo.Implementation) {
|
|
childPlan := child.GetPlan()
|
|
sort := plannercore.PhysicalSort{
|
|
ByItems: make([]*util.ByItems, 0, len(reqProp.Items)),
|
|
}.Init(childPlan.SCtx(), childPlan.Stats(), childPlan.SelectBlockOffset(), &property.PhysicalProperty{ExpectedCnt: math.MaxFloat64})
|
|
for _, item := range reqProp.Items {
|
|
item := &util.ByItems{
|
|
Expr: item.Col,
|
|
Desc: item.Desc,
|
|
}
|
|
sort.ByItems = append(sort.ByItems, item)
|
|
}
|
|
impl = implementation.NewSortImpl(sort).AttachChildren(child)
|
|
return
|
|
}
|
|
|
|
// GetEnforceCost calculates cost of sort operator.
|
|
func (e *OrderEnforcer) GetEnforceCost(g *memo.Group) float64 {
|
|
// We need a SessionCtx to calculate the cost of a sort.
|
|
sctx := g.Equivalents.Front().Value.(*memo.GroupExpr).ExprNode.SCtx()
|
|
sort := plannercore.PhysicalSort{}.Init(sctx, g.Prop.Stats, 0, nil)
|
|
cost := sort.GetCost(g.Prop.Stats.RowCount, g.Prop.Schema)
|
|
return cost
|
|
}
|
|
|