Skip to content

Commit

Permalink
planner: support basic Show in cascades planner (pingcap#12185)
Browse files Browse the repository at this point in the history
  • Loading branch information
zz-jason authored and sre-bot committed Sep 17, 2019
1 parent 5f6b22c commit e685ce4
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 26 deletions.
31 changes: 29 additions & 2 deletions planner/cascades/implementation_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ type ImplementationRule interface {
OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) (memo.Implementation, error)
}

// GetImplementationRules gets the all the candidate implementation rules based
// on the logical plan node.
// GetImplementationRules gets all the candidate implementation rules for the
// logical plan node.
func GetImplementationRules(node plannercore.LogicalPlan) []ImplementationRule {
operand := memo.GetOperand(node)
return implementationMap[operand]
Expand All @@ -49,6 +49,9 @@ var implementationMap = map[memo.Operand][]ImplementationRule{
memo.OperandTableGather: {
&ImplTableGather{},
},
memo.OperandShow: {
&ImplShow{},
},
}

// ImplTableDual implements LogicalTableDual as PhysicalTableDual.
Expand Down Expand Up @@ -137,3 +140,27 @@ func (r *ImplTableScan) OnImplement(expr *memo.GroupExpr, reqProp *property.Phys
tblCols, tblColHists := logicalScan.Source.TblCols, logicalScan.Source.TblColHists
return impl.NewTableScanImpl(ts, tblCols, tblColHists), nil
}

// ImplShow is the implementation rule which implements LogicalShow to
// PhysicalShow.
type ImplShow struct {
}

// Match implements ImplementationRule Match interface.
func (r *ImplShow) Match(expr *memo.GroupExpr, prop *property.PhysicalProperty) (matched bool) {
return prop.IsEmpty()
}

// OnImplement implements ImplementationRule OnImplement interface.
func (r *ImplShow) OnImplement(expr *memo.GroupExpr, reqProp *property.PhysicalProperty) (memo.Implementation, error) {
logicProp := expr.Group.Prop
show := expr.ExprNode.(*plannercore.LogicalShow)

// TODO(zz-jason): unifying LogicalShow and PhysicalShow to a single
// struct. So that we don't need to create a new PhysicalShow object, which
// can help us to reduce the gc presure of golang runtime and improve the
// overall performance.
showPhys := plannercore.PhysicalShow{ShowContents: show.ShowContents}.Init(show.SCtx())
showPhys.SetSchema(logicProp.Schema)
return impl.NewShowImpl(showPhys), nil
}
11 changes: 11 additions & 0 deletions planner/cascades/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,14 @@ func (s *testIntegrationSuite) TestPKIsHandleRangeScan(c *C) {
))
tk.MustQuery("select b from t where a > 1 and a < 3").Check(testkit.Rows())
}

func (s *testIntegrationSuite) TestBasicShow(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int primary key, b int)")
tk.MustExec("set session tidb_enable_cascades_planner = 1")
tk.MustQuery("desc t").Check(testkit.Rows(
"a int(11) NO PRI <nil> ",
"b int(11) YES <nil> ",
))
}
34 changes: 33 additions & 1 deletion planner/cascades/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,32 @@ import (

// FindBestPlan is the optimization entrance of the cascades planner. The
// optimization is composed of 2 phases: exploration and implementation.
//
//------------------------------------------------------------------------------
// Phase 1: Exploration
//------------------------------------------------------------------------------
//
// The target of this phase is to explore all the logically equivalent
// expressions by exploring all the equivalent group expressions of each group.
//
// At the very beginning, there is only one group expression in a Group. After
// applying some transformation rules on certain expressions of the Group, all
// the equivalent expressions are found and stored in the Group. This procedure
// can be regarded as searching for a weak connected component in a directed
// graph, where nodes are expressions and directed edges are the transformation
// rules.
//
//------------------------------------------------------------------------------
// Phase 2: Implementation
//------------------------------------------------------------------------------
//
// The target of this phase is to search the best physical plan for a Group
// which satisfies a certain required physical property.
//
// In this phase, we need to enumerate all the applicable implementation rules
// for each expression in each group under the required physical property. A
// memo structure is used for a group to reduce the repeated search on the same
// required physical property.
func FindBestPlan(sctx sessionctx.Context, logical plannercore.LogicalPlan) (p plannercore.PhysicalPlan, err error) {
rootGroup := convert2Group(logical)
err = onPhaseExploration(sctx, rootGroup)
Expand Down Expand Up @@ -178,7 +204,13 @@ func onPhaseImplementation(sctx sessionctx.Context, g *memo.Group) (plannercore.
return impl.GetPlan(), nil
}

// implGroup picks one implementation with lowest cost for a Group, which satisfies specified physical property.
// implGroup finds the best Implementation which satisfies the required
// physical property for a Group. The best Implementation should have the
// lowest cost among all the applicable Implementations.
//
// g: the Group to be implemented.
// reqPhysProp: the required physical property.
// costLimit: the maximum cost of all the Implementations.
func implGroup(g *memo.Group, reqPhysProp *property.PhysicalProperty, costLimit float64) (memo.Implementation, error) {
groupImpl := g.GetImpl(reqPhysProp)
if groupImpl != nil {
Expand Down
2 changes: 1 addition & 1 deletion planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (p *LogicalShow) findBestTask(prop *property.PhysicalProperty) (task, error
if !prop.IsEmpty() {
return invalidTask, nil
}
pShow := PhysicalShow{baseShowContent: p.baseShowContent}.Init(p.ctx)
pShow := PhysicalShow{ShowContents: p.ShowContents}.Init(p.ctx)
pShow.SetSchema(p.schema)
return &rootTask{p: pShow}, nil
}
Expand Down
5 changes: 3 additions & 2 deletions planner/core/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,8 @@ func extractCorColumnsBySchema(p LogicalPlan, schema *expression.Schema) []*expr
return resultCorCols[:length]
}

type baseShowContent struct {
// ShowContents stores the contents for the `SHOW` statement.
type ShowContents struct {
Tp ast.ShowStmtType // Databases/Tables/Columns/....
DBName string
Table *ast.TableName // Used for showing columns.
Expand All @@ -861,5 +862,5 @@ type baseShowContent struct {
// LogicalShow represents a show plan.
type LogicalShow struct {
logicalSchemaProducer
baseShowContent
ShowContents
}
2 changes: 1 addition & 1 deletion planner/core/physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ func CollectPlanStatsVersion(plan PhysicalPlan, statsInfos map[string]uint64) ma
type PhysicalShow struct {
physicalSchemaProducer

baseShowContent
ShowContents
}

// BuildMergeJoinPlan builds a PhysicalMergeJoin from the given fields. Currently, it is only used for test purpose.
Expand Down
2 changes: 1 addition & 1 deletion planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1385,7 +1385,7 @@ func splitWhere(where ast.ExprNode) []ast.ExprNode {

func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, error) {
p := LogicalShow{
baseShowContent: baseShowContent{
ShowContents: ShowContents{
Tp: show.Tp,
DBName: show.DBName,
Table: show.Table,
Expand Down
5 changes: 4 additions & 1 deletion planner/implementation/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ type baseImpl struct {
}

func (impl *baseImpl) CalcCost(outCount float64, childCosts []float64, children ...*memo.Group) float64 {
impl.cost = childCosts[0]
impl.cost = 0
for _, childCost := range childCosts {
impl.cost += childCost
}
return impl.cost
}

Expand Down
10 changes: 10 additions & 0 deletions planner/implementation/simple_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,13 @@ type ProjectionImpl struct {
func NewProjectionImpl(proj *plannercore.PhysicalProjection) *ProjectionImpl {
return &ProjectionImpl{baseImpl{plan: proj}}
}

// ShowImpl is the Implementation of PhysicalShow.
type ShowImpl struct {
baseImpl
}

// NewShowImpl creates a new ShowImpl.
func NewShowImpl(show *plannercore.PhysicalShow) *ShowImpl {
return &ShowImpl{baseImpl: baseImpl{plan: show}}
}
38 changes: 21 additions & 17 deletions planner/memo/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,41 @@ type Operand int
const (
// OperandAny is a placeholder for any Operand.
OperandAny Operand = iota
// OperandJoin for LogicalJoin.
// OperandJoin is the operand for LogicalJoin.
OperandJoin
// OperandAggregation for LogicalAggregation.
// OperandAggregation is the operand for LogicalAggregation.
OperandAggregation
// OperandProjection for LogicalProjection.
// OperandProjection is the operand for LogicalProjection.
OperandProjection
// OperandSelection for LogicalSelection.
// OperandSelection is the operand for LogicalSelection.
OperandSelection
// OperandApply for LogicalApply.
// OperandApply is the operand for LogicalApply.
OperandApply
// OperandMaxOneRow for LogicalMaxOneRow.
// OperandMaxOneRow is the operand for LogicalMaxOneRow.
OperandMaxOneRow
// OperandTableDual for LogicalTableDual.
// OperandTableDual is the operand for LogicalTableDual.
OperandTableDual
// OperandDataSource for DataSource.
// OperandDataSource is the operand for DataSource.
OperandDataSource
// OperandUnionScan for LogicalUnionScan.
// OperandUnionScan is the operand for LogicalUnionScan.
OperandUnionScan
// OperandUnionAll for LogicalUnionAll.
// OperandUnionAll is the operand for LogicalUnionAll.
OperandUnionAll
// OperandSort for LogicalSort.
// OperandSort is the operand for LogicalSort.
OperandSort
// OperandTopN for LogicalTopN.
// OperandTopN is the operand for LogicalTopN.
OperandTopN
// OperandLock for LogicalLock.
// OperandLock is the operand for LogicalLock.
OperandLock
// OperandLimit for LogicalLimit.
// OperandLimit is the operand for LogicalLimit.
OperandLimit
// OperandTableGather for TableGather.
// OperandTableGather is the operand for TableGather.
OperandTableGather
// OperandTableScan for TableScan.
// OperandTableScan is the operand for TableScan.
OperandTableScan
// OperandUnsupported is upper bound of defined Operand yet.
// OperandShow is the operand for Show.
OperandShow
// OperandUnsupported is the operand for unsupported operators.
OperandUnsupported
)

Expand Down Expand Up @@ -98,6 +100,8 @@ func GetOperand(p plannercore.LogicalPlan) Operand {
return OperandTableGather
case *plannercore.TableScan:
return OperandTableScan
case *plannercore.LogicalShow:
return OperandShow
default:
return OperandUnsupported
}
Expand Down

0 comments on commit e685ce4

Please sign in to comment.