Skip to content

Commit

Permalink
planner/cascades: introduce TransformationRuleBatch & add rule Inject…
Browse files Browse the repository at this point in the history
…ProjectionBelowTopN (pingcap#14504)
  • Loading branch information
francis0407 authored Feb 29, 2020
1 parent 3166ff4 commit ded862f
Show file tree
Hide file tree
Showing 13 changed files with 802 additions and 512 deletions.
57 changes: 27 additions & 30 deletions planner/cascades/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ var DefaultOptimizer = NewOptimizer()

// Optimizer is the struct for cascades optimizer.
type Optimizer struct {
transformationRuleMap map[memo.Operand][]Transformation
implementationRuleMap map[memo.Operand][]ImplementationRule
transformationRuleBatches []TransformationRuleBatch
implementationRuleMap map[memo.Operand][]ImplementationRule
}

// NewOptimizer returns a cascades optimizer with default transformation
// rules and implementation rules.
func NewOptimizer() *Optimizer {
return &Optimizer{
transformationRuleMap: defaultTransformationMap,
implementationRuleMap: defaultImplementationMap,
transformationRuleBatches: DefaultRuleBatches,
implementationRuleMap: defaultImplementationMap,
}
}

// ResetTransformationRules resets the transformationRuleMap of the optimizer, and returns the optimizer.
func (opt *Optimizer) ResetTransformationRules(rules map[memo.Operand][]Transformation) *Optimizer {
opt.transformationRuleMap = rules
// ResetTransformationRules resets the transformationRuleBatches of the optimizer, and returns the optimizer.
func (opt *Optimizer) ResetTransformationRules(ruleBatches ...TransformationRuleBatch) *Optimizer {
opt.transformationRuleBatches = ruleBatches
return opt
}

Expand All @@ -55,12 +55,6 @@ func (opt *Optimizer) ResetImplementationRules(rules map[memo.Operand][]Implemen
return opt
}

// GetTransformationRules gets the all the candidate Transformation rules of the optimizer
// based on the logical plan node.
func (opt *Optimizer) GetTransformationRules(node plannercore.LogicalPlan) []Transformation {
return opt.transformationRuleMap[memo.GetOperand(node)]
}

// GetImplementationRules gets all the candidate implementation rules of the optimizer
// for the logical plan node.
func (opt *Optimizer) GetImplementationRules(node plannercore.LogicalPlan) []ImplementationRule {
Expand Down Expand Up @@ -129,38 +123,40 @@ func (opt *Optimizer) onPhasePreprocessing(sctx sessionctx.Context, plan planner
}

func (opt *Optimizer) onPhaseExploration(sctx sessionctx.Context, g *memo.Group) error {
for !g.Explored {
err := opt.exploreGroup(g)
if err != nil {
return err
for round, ruleBatch := range opt.transformationRuleBatches {
for !g.Explored(round) {
err := opt.exploreGroup(g, round, ruleBatch)
if err != nil {
return err
}
}
}
return nil
}

func (opt *Optimizer) exploreGroup(g *memo.Group) error {
if g.Explored {
func (opt *Optimizer) exploreGroup(g *memo.Group, round int, ruleBatch TransformationRuleBatch) error {
if g.Explored(round) {
return nil
}
g.Explored = true
g.SetExplored(round)

for elem := g.Equivalents.Front(); elem != nil; elem = elem.Next() {
curExpr := elem.Value.(*memo.GroupExpr)
if curExpr.Explored {
if curExpr.Explored(round) {
continue
}
curExpr.Explored = true
curExpr.SetExplored(round)

// Explore child groups firstly.
for _, childGroup := range curExpr.Children {
for !childGroup.Explored {
if err := opt.exploreGroup(childGroup); err != nil {
for !childGroup.Explored(round) {
if err := opt.exploreGroup(childGroup, round, ruleBatch); err != nil {
return err
}
}
}

eraseCur, err := opt.findMoreEquiv(g, elem)
eraseCur, err := opt.findMoreEquiv(g, elem, round, ruleBatch)
if err != nil {
return err
}
Expand All @@ -172,11 +168,12 @@ func (opt *Optimizer) exploreGroup(g *memo.Group) error {
}

// findMoreEquiv finds and applies the matched transformation rules.
func (opt *Optimizer) findMoreEquiv(g *memo.Group, elem *list.Element) (eraseCur bool, err error) {
func (opt *Optimizer) findMoreEquiv(g *memo.Group, elem *list.Element, round int, ruleBatch TransformationRuleBatch) (eraseCur bool, err error) {
expr := elem.Value.(*memo.GroupExpr)
for _, rule := range opt.GetTransformationRules(expr.ExprNode) {
operand := memo.GetOperand(expr.ExprNode)
for _, rule := range ruleBatch[operand] {
pattern := rule.GetPattern()
if !pattern.Operand.Match(memo.GetOperand(expr.ExprNode)) {
if !pattern.Operand.Match(operand) {
continue
}
// Create a binding of the current Group expression and the pattern of
Expand All @@ -198,7 +195,7 @@ func (opt *Optimizer) findMoreEquiv(g *memo.Group, elem *list.Element) (eraseCur
g.Insert(e)
}
// If we delete all of the other GroupExprs, we can break the search.
g.Explored = true
g.SetExplored(round)
return false, nil
}

Expand All @@ -210,7 +207,7 @@ func (opt *Optimizer) findMoreEquiv(g *memo.Group, elem *list.Element) (eraseCur
// If the new Group expression is successfully inserted into the
// current Group, mark the Group as unexplored to enable the exploration
// on the new Group expressions.
g.Explored = false
g.SetUnexplored(round)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions planner/cascades/optimize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (s *testCascadesSuite) TestPreparePossibleProperties(c *C) {
},
})
defer func() {
s.optimizer.ResetTransformationRules(defaultTransformationMap)
s.optimizer.ResetTransformationRules(DefaultRuleBatches...)
}()
stmt, err := s.ParseOneStmt("select f, sum(a) from t group by f", "", "")
c.Assert(err, IsNil)
Expand Down Expand Up @@ -187,7 +187,7 @@ func (s *testCascadesSuite) TestAppliedRuleSet(c *C) {
},
})
defer func() {
s.optimizer.ResetTransformationRules(defaultTransformationMap)
s.optimizer.ResetTransformationRules(DefaultRuleBatches...)
}()
stmt, err := s.ParseOneStmt("select 1", "", "")
c.Assert(err, IsNil)
Expand Down
2 changes: 1 addition & 1 deletion planner/cascades/stringer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (s *testStringerSuite) TestGroupStringer(c *C) {
},
})
defer func() {
s.optimizer.ResetTransformationRules(defaultTransformationMap)
s.optimizer.ResetTransformationRules(DefaultRuleBatches...)
}()
var input []string
var output []struct {
Expand Down
3 changes: 2 additions & 1 deletion planner/cascades/testdata/integration_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
"select b from t order by b limit 3",
"select a from t order by a limit 1 offset 2",
"select * from ((select a as aa from t t1) union all (select b as aa from t t2)) as t3 order by aa",
"select a, b, lag(a,1) over (order by b) from t order by b"
"select a, b, lag(a,1) over (order by b) from t order by b",
"select * from (select a+1 as c, a+b as d from t) as t1 order by c+d limit 10"
]
},
{
Expand Down
Loading

0 comments on commit ded862f

Please sign in to comment.