From f7edb2b11186096b55c97112e2d4a2e733f4fcc9 Mon Sep 17 00:00:00 2001 From: Zhang Jian Date: Thu, 2 Aug 2018 21:22:53 +0800 Subject: [PATCH] plan: always chose the smaller child as outer for IndexJoin (#7019) (#7227) --- plan/gen_physical_plans.go | 35 +++++++++------ plan/initialize.go | 38 ++++++++-------- plan/logical_plans.go | 4 +- plan/physical_plan_builder.go | 4 +- plan/plan.go | 15 ++++--- plan/planbuilder.go | 2 +- plan/stats.go | 82 ++++++++++++++++++----------------- 7 files changed, 97 insertions(+), 83 deletions(-) diff --git a/plan/gen_physical_plans.go b/plan/gen_physical_plans.go index 0f8ad88b66ddf..178f84254de37 100644 --- a/plan/gen_physical_plans.go +++ b/plan/gen_physical_plans.go @@ -385,22 +385,29 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *requiredProp) ([]PhysicalPlan, boo plans = append(plans, join...) } case InnerJoin: - join := p.getIndexJoinByOuterIdx(prop, 0) - if join != nil { - // If the plan is not nil and matches the hint, return it directly. - if leftOuter { - return join, true - } - plans = append(plans, join...) + lhsCardinality := p.Children()[0].StatsInfo().Count() + rhsCardinality := p.Children()[1].StatsInfo().Count() + + leftJoins := p.getIndexJoinByOuterIdx(prop, 0) + if leftOuter && leftJoins != nil { + return leftJoins, true } - join = p.getIndexJoinByOuterIdx(prop, 1) - if join != nil { - // If the plan is not nil and matches the hint, return it directly. - if rightOuter { - return join, true - } - plans = append(plans, join...) + + rightJoins := p.getIndexJoinByOuterIdx(prop, 1) + if rightOuter && rightJoins != nil { + return rightJoins, true } + + if leftJoins != nil && lhsCardinality < rhsCardinality { + return leftJoins, leftOuter + } + + if rightJoins != nil && rhsCardinality < lhsCardinality { + return rightJoins, rightOuter + } + + plans = append(plans, leftJoins...) + plans = append(plans, rightJoins...) } return plans, false } diff --git a/plan/initialize.go b/plan/initialize.go index 7af3608ac21d2..edc981c1482df 100644 --- a/plan/initialize.go +++ b/plan/initialize.go @@ -105,7 +105,7 @@ func (p LogicalSelection) init(ctx sessionctx.Context) *LogicalSelection { return &p } -func (p PhysicalSelection) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalSelection { +func (p PhysicalSelection) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalSelection { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeSel, &p) p.childrenReqProps = props p.stats = stats @@ -122,7 +122,7 @@ func (p LogicalProjection) init(ctx sessionctx.Context) *LogicalProjection { return &p } -func (p PhysicalProjection) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalProjection { +func (p PhysicalProjection) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalProjection { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeProj, &p) p.childrenReqProps = props p.stats = stats @@ -134,7 +134,7 @@ func (p LogicalUnionAll) init(ctx sessionctx.Context) *LogicalUnionAll { return &p } -func (p PhysicalUnionAll) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalUnionAll { +func (p PhysicalUnionAll) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalUnionAll { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeUnion, &p) p.childrenReqProps = props p.stats = stats @@ -146,7 +146,7 @@ func (ls LogicalSort) init(ctx sessionctx.Context) *LogicalSort { return &ls } -func (p PhysicalSort) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalSort { +func (p PhysicalSort) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalSort { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeSort, &p) p.childrenReqProps = props p.stats = stats @@ -164,7 +164,7 @@ func (lt LogicalTopN) init(ctx sessionctx.Context) *LogicalTopN { return < } -func (p PhysicalTopN) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalTopN { +func (p PhysicalTopN) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalTopN { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeTopN, &p) p.childrenReqProps = props p.stats = stats @@ -176,7 +176,7 @@ func (p LogicalLimit) init(ctx sessionctx.Context) *LogicalLimit { return &p } -func (p PhysicalLimit) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalLimit { +func (p PhysicalLimit) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalLimit { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeLimit, &p) p.childrenReqProps = props p.stats = stats @@ -188,7 +188,7 @@ func (p LogicalTableDual) init(ctx sessionctx.Context) *LogicalTableDual { return &p } -func (p PhysicalTableDual) init(ctx sessionctx.Context, stats *statsInfo) *PhysicalTableDual { +func (p PhysicalTableDual) init(ctx sessionctx.Context, stats *StatsInfo) *PhysicalTableDual { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeDual, &p) p.stats = stats return &p @@ -199,7 +199,7 @@ func (p LogicalExists) init(ctx sessionctx.Context) *LogicalExists { return &p } -func (p PhysicalExists) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalExists { +func (p PhysicalExists) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalExists { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeExists, &p) p.childrenReqProps = props p.stats = stats @@ -211,7 +211,7 @@ func (p LogicalMaxOneRow) init(ctx sessionctx.Context) *LogicalMaxOneRow { return &p } -func (p PhysicalMaxOneRow) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalMaxOneRow { +func (p PhysicalMaxOneRow) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalMaxOneRow { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeMaxOneRow, &p) p.childrenReqProps = props p.stats = stats @@ -243,7 +243,7 @@ func (p LogicalLock) init(ctx sessionctx.Context) *LogicalLock { return &p } -func (p PhysicalLock) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalLock { +func (p PhysicalLock) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalLock { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeLock, &p) p.childrenReqProps = props p.stats = stats @@ -260,13 +260,13 @@ func (p PhysicalIndexScan) init(ctx sessionctx.Context) *PhysicalIndexScan { return &p } -func (p PhysicalMemTable) init(ctx sessionctx.Context, stats *statsInfo) *PhysicalMemTable { +func (p PhysicalMemTable) init(ctx sessionctx.Context, stats *StatsInfo) *PhysicalMemTable { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeMemTableScan, &p) p.stats = stats return &p } -func (p PhysicalHashJoin) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalHashJoin { +func (p PhysicalHashJoin) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalHashJoin { tp := TypeHashRightJoin if p.InnerChildIdx == 1 { tp = TypeHashLeftJoin @@ -277,19 +277,19 @@ func (p PhysicalHashJoin) init(ctx sessionctx.Context, stats *statsInfo, props . return &p } -func (p PhysicalMergeJoin) init(ctx sessionctx.Context, stats *statsInfo) *PhysicalMergeJoin { +func (p PhysicalMergeJoin) init(ctx sessionctx.Context, stats *StatsInfo) *PhysicalMergeJoin { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeMergeJoin, &p) p.stats = stats return &p } -func (base basePhysicalAgg) init(ctx sessionctx.Context, stats *statsInfo) *basePhysicalAgg { +func (base basePhysicalAgg) init(ctx sessionctx.Context, stats *StatsInfo) *basePhysicalAgg { base.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeHashAgg, &base) base.stats = stats return &base } -func (base basePhysicalAgg) initForHash(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalHashAgg { +func (base basePhysicalAgg) initForHash(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalHashAgg { p := &PhysicalHashAgg{base} p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeHashAgg, p) p.childrenReqProps = props @@ -297,7 +297,7 @@ func (base basePhysicalAgg) initForHash(ctx sessionctx.Context, stats *statsInfo return p } -func (base basePhysicalAgg) initForStream(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalStreamAgg { +func (base basePhysicalAgg) initForStream(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalStreamAgg { p := &PhysicalStreamAgg{base} p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeStreamAgg, p) p.childrenReqProps = props @@ -305,14 +305,14 @@ func (base basePhysicalAgg) initForStream(ctx sessionctx.Context, stats *statsIn return p } -func (p PhysicalApply) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalApply { +func (p PhysicalApply) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalApply { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeApply, &p) p.childrenReqProps = props p.stats = stats return &p } -func (p PhysicalUnionScan) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalUnionScan { +func (p PhysicalUnionScan) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalUnionScan { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeUnionScan, &p) p.childrenReqProps = props p.stats = stats @@ -348,7 +348,7 @@ func (p PhysicalIndexReader) init(ctx sessionctx.Context) *PhysicalIndexReader { return &p } -func (p PhysicalIndexJoin) init(ctx sessionctx.Context, stats *statsInfo, props ...*requiredProp) *PhysicalIndexJoin { +func (p PhysicalIndexJoin) init(ctx sessionctx.Context, stats *StatsInfo, props ...*requiredProp) *PhysicalIndexJoin { p.basePhysicalPlan = newBasePhysicalPlan(ctx, TypeIndexJoin, &p) p.childrenReqProps = props p.stats = stats diff --git a/plan/logical_plans.go b/plan/logical_plans.go index 083016e2c8aa4..76907bafe8009 100644 --- a/plan/logical_plans.go +++ b/plan/logical_plans.go @@ -299,8 +299,8 @@ type DataSource struct { // relevantIndices means the indices match the push down conditions relevantIndices []bool - // statsAfterSelect is the statsInfo for dataSource and selection. - statsAfterSelect *statsInfo + // statsAfterSelect is the StatsInfo for dataSource and selection. + statsAfterSelect *StatsInfo statisticTable *statistics.Table diff --git a/plan/physical_plan_builder.go b/plan/physical_plan_builder.go index 4926106e18fb2..4c48da0200680 100644 --- a/plan/physical_plan_builder.go +++ b/plan/physical_plan_builder.go @@ -406,7 +406,7 @@ func (is *PhysicalIndexScan) addPushedDownSelection(copTask *copTask, p *DataSou selectivity := path.countAfterIndex / path.countAfterAccess count = is.stats.count * selectivity } - stats := &statsInfo{count: count} + stats := &StatsInfo{count: count} indexSel := PhysicalSelection{Conditions: indexConds}.init(is.ctx, stats) indexSel.SetChildren(is) copTask.indexPlan = indexSel @@ -565,7 +565,7 @@ func (ds *DataSource) convertToTableScan(prop *requiredProp, path *accessPath) ( return task, nil } -func (ts *PhysicalTableScan) addPushedDownSelection(copTask *copTask, stats *statsInfo) { +func (ts *PhysicalTableScan) addPushedDownSelection(copTask *copTask, stats *StatsInfo) { // Add filter condition to table plan now. if len(ts.filterCondition) > 0 { copTask.cst += copTask.count() * cpuFactor diff --git a/plan/plan.go b/plan/plan.go index 84344be0f5417..6ce62a1bcdcbf 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -38,6 +38,9 @@ type Plan interface { replaceExprColumns(replace map[string]*expression.Column) context() sessionctx.Context + + // StatsInfo will return the StatsInfo for this plan. + StatsInfo() *StatsInfo } // taskType is the type of execution task. @@ -161,7 +164,7 @@ type LogicalPlan interface { pushDownTopN(topN *LogicalTopN) LogicalPlan // deriveStats derives statistic info between plans. - deriveStats() (*statsInfo, error) + deriveStats() (*StatsInfo, error) // preparePossibleProperties is only used for join and aggregation. Like group by a,b,c, all permutation of (a,b,c) is // valid, but the ordered indices in leaf plan is limited. So we can get all possible order properties by a pre-walking. @@ -205,9 +208,6 @@ type PhysicalPlan interface { // getChildReqProps gets the required property by child index. getChildReqProps(idx int) *requiredProp - // StatsInfo will return the statsInfo for this plan. - StatsInfo() *statsInfo - // Get all the children. Children() []PhysicalPlan @@ -270,6 +270,11 @@ func (p *baseLogicalPlan) buildKeyInfo() { } } +// StatsInfo implements the Plan.StatsInfo interface. +func (p *DataSource) StatsInfo() *StatsInfo { + return p.statsAfterSelect +} + func newBasePlan(ctx sessionctx.Context, tp string) basePlan { ctx.GetSessionVars().PlanID++ id := ctx.GetSessionVars().PlanID @@ -317,7 +322,7 @@ type basePlan struct { tp string id int ctx sessionctx.Context - stats *statsInfo + stats *StatsInfo } func (p *basePlan) replaceExprColumns(replace map[string]*expression.Column) { diff --git a/plan/planbuilder.go b/plan/planbuilder.go index 4216159caf6fd..4fc9b10a0f3a0 100644 --- a/plan/planbuilder.go +++ b/plan/planbuilder.go @@ -420,7 +420,7 @@ func (b *planBuilder) buildCheckIndex(dbName model.CIStr, as *ast.AdminStmt) Pla Ranges: ranger.FullNewRange(), KeepOrder: false, }.init(b.ctx) - is.stats = &statsInfo{} + is.stats = &StatsInfo{} cop := &copTask{indexPlan: is} // It's double read case. ts := PhysicalTableScan{Columns: columns, Table: is.Table}.init(b.ctx) diff --git a/plan/stats.go b/plan/stats.go index 3d26c43d5f354..cc77143331b4c 100644 --- a/plan/stats.go +++ b/plan/stats.go @@ -22,23 +22,25 @@ import ( log "github.com/sirupsen/logrus" ) -// statsInfo stores the basic information of statistics for the plan's output. It is used for cost estimation. -type statsInfo struct { +// StatsInfo stores the basic information of statistics for the plan's output. It is used for cost estimation. +type StatsInfo struct { count float64 cardinality []float64 } -func (s *statsInfo) String() string { +// String returns the string representation of the StatsInfo. +func (s *StatsInfo) String() string { return fmt.Sprintf("count %v, cardinality %v", s.count, s.cardinality) } -func (s *statsInfo) Count() int64 { +// Count returns the count of the StatsInfo. +func (s *StatsInfo) Count() int64 { return int64(s.count) } // scale receives a selectivity and multiplies it with count and cardinality. -func (s *statsInfo) scale(factor float64) *statsInfo { - profile := &statsInfo{ +func (s *StatsInfo) scale(factor float64) *StatsInfo { + profile := &StatsInfo{ count: s.count * factor, cardinality: make([]float64, len(s.cardinality)), } @@ -48,8 +50,8 @@ func (s *statsInfo) scale(factor float64) *statsInfo { return profile } -// We try to scale statsInfo to an expectCnt which must be smaller than the derived cnt. -func (s *statsInfo) scaleByExpectCnt(expectCnt float64) *statsInfo { +// We try to scale StatsInfo to an expectCnt which must be smaller than the derived cnt. +func (s *StatsInfo) scaleByExpectCnt(expectCnt float64) *StatsInfo { if expectCnt > s.count { return s } @@ -59,12 +61,12 @@ func (s *statsInfo) scaleByExpectCnt(expectCnt float64) *statsInfo { return s } -func (p *basePhysicalPlan) StatsInfo() *statsInfo { +func (p *basePlan) StatsInfo() *StatsInfo { return p.stats } -func (p *LogicalTableDual) deriveStats() (*statsInfo, error) { - profile := &statsInfo{ +func (p *LogicalTableDual) deriveStats() (*StatsInfo, error) { + profile := &StatsInfo{ count: float64(p.RowCount), cardinality: make([]float64, p.Schema().Len()), } @@ -75,7 +77,7 @@ func (p *LogicalTableDual) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (p *baseLogicalPlan) deriveStats() (*statsInfo, error) { +func (p *baseLogicalPlan) deriveStats() (*StatsInfo, error) { if len(p.children) > 1 { panic("LogicalPlans with more than one child should implement their own deriveStats().") } @@ -86,7 +88,7 @@ func (p *baseLogicalPlan) deriveStats() (*statsInfo, error) { return p.stats, errors.Trace(err) } - profile := &statsInfo{ + profile := &StatsInfo{ count: float64(1), cardinality: make([]float64, p.self.Schema().Len()), } @@ -97,8 +99,8 @@ func (p *baseLogicalPlan) deriveStats() (*statsInfo, error) { return profile, nil } -func (ds *DataSource) getStatsByFilter(conds expression.CNFExprs) *statsInfo { - profile := &statsInfo{ +func (ds *DataSource) getStatsByFilter(conds expression.CNFExprs) *StatsInfo { + profile := &StatsInfo{ count: float64(ds.statisticTable.Count), cardinality: make([]float64, len(ds.Columns)), } @@ -120,7 +122,7 @@ func (ds *DataSource) getStatsByFilter(conds expression.CNFExprs) *statsInfo { return profile.scale(selectivity) } -func (ds *DataSource) deriveStats() (*statsInfo, error) { +func (ds *DataSource) deriveStats() (*StatsInfo, error) { // PushDownNot here can convert query 'not (a != 1)' to 'a = 1'. for i, expr := range ds.pushedDownConds { ds.pushedDownConds[i] = expression.PushDownNot(nil, expr, false) @@ -154,7 +156,7 @@ func (ds *DataSource) deriveStats() (*statsInfo, error) { return ds.statsAfterSelect, nil } -func (p *LogicalSelection) deriveStats() (*statsInfo, error) { +func (p *LogicalSelection) deriveStats() (*StatsInfo, error) { childProfile, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) @@ -163,8 +165,8 @@ func (p *LogicalSelection) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (p *LogicalUnionAll) deriveStats() (*statsInfo, error) { - p.stats = &statsInfo{ +func (p *LogicalUnionAll) deriveStats() (*StatsInfo, error) { + p.stats = &StatsInfo{ cardinality: make([]float64, p.Schema().Len()), } for _, child := range p.children { @@ -180,12 +182,12 @@ func (p *LogicalUnionAll) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (p *LogicalLimit) deriveStats() (*statsInfo, error) { +func (p *LogicalLimit) deriveStats() (*StatsInfo, error) { childProfile, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) } - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: math.Min(float64(p.Count), childProfile.count), cardinality: make([]float64, len(childProfile.cardinality)), } @@ -195,12 +197,12 @@ func (p *LogicalLimit) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (lt *LogicalTopN) deriveStats() (*statsInfo, error) { +func (lt *LogicalTopN) deriveStats() (*StatsInfo, error) { childProfile, err := lt.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) } - lt.stats = &statsInfo{ + lt.stats = &StatsInfo{ count: math.Min(float64(lt.Count), childProfile.count), cardinality: make([]float64, len(childProfile.cardinality)), } @@ -212,7 +214,7 @@ func (lt *LogicalTopN) deriveStats() (*statsInfo, error) { // getCardinality will return the cardinality of a couple of columns. We simply return the max one, because we cannot know // the cardinality for multi-dimension attributes properly. This is a simple and naive scheme of cardinality estimation. -func getCardinality(cols []*expression.Column, schema *expression.Schema, profile *statsInfo) float64 { +func getCardinality(cols []*expression.Column, schema *expression.Schema, profile *StatsInfo) float64 { indices := schema.ColumnsIndices(cols) if indices == nil { log.Errorf("Cannot find column %s indices from schema %s", cols, schema) @@ -226,12 +228,12 @@ func getCardinality(cols []*expression.Column, schema *expression.Schema, profil return cardinality } -func (p *LogicalProjection) deriveStats() (*statsInfo, error) { +func (p *LogicalProjection) deriveStats() (*StatsInfo, error) { childProfile, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) } - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: childProfile.count, cardinality: make([]float64, len(p.Exprs)), } @@ -242,7 +244,7 @@ func (p *LogicalProjection) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (la *LogicalAggregation) deriveStats() (*statsInfo, error) { +func (la *LogicalAggregation) deriveStats() (*StatsInfo, error) { childProfile, err := la.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) @@ -253,7 +255,7 @@ func (la *LogicalAggregation) deriveStats() (*statsInfo, error) { gbyCols = append(gbyCols, cols...) } cardinality := getCardinality(gbyCols, la.children[0].Schema(), childProfile) - la.stats = &statsInfo{ + la.stats = &StatsInfo{ count: cardinality, cardinality: make([]float64, la.schema.Len()), } @@ -265,14 +267,14 @@ func (la *LogicalAggregation) deriveStats() (*statsInfo, error) { return la.stats, nil } -// deriveStats prepares statsInfo. +// deriveStats prepares StatsInfo. // If the type of join is SemiJoin, the selectivity of it will be same as selection's. // If the type of join is LeftOuterSemiJoin, it will not add or remove any row. The last column is a boolean value, whose cardinality should be two. // If the type of join is inner/outer join, the output of join(s, t) should be N(s) * N(t) / (V(s.key) * V(t.key)) * Min(s.key, t.key). // N(s) stands for the number of rows in relation s. V(s.key) means the cardinality of join key in s. // This is a quite simple strategy: We assume every bucket of relation which will participate join has the same number of rows, and apply cross join for // every matched bucket. -func (p *LogicalJoin) deriveStats() (*statsInfo, error) { +func (p *LogicalJoin) deriveStats() (*StatsInfo, error) { leftProfile, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) @@ -282,7 +284,7 @@ func (p *LogicalJoin) deriveStats() (*statsInfo, error) { return nil, errors.Trace(err) } if p.JoinType == SemiJoin || p.JoinType == AntiSemiJoin { - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: leftProfile.count * selectionFactor, cardinality: make([]float64, len(leftProfile.cardinality)), } @@ -292,7 +294,7 @@ func (p *LogicalJoin) deriveStats() (*statsInfo, error) { return p.stats, nil } if p.JoinType == LeftOuterSemiJoin || p.JoinType == AntiLeftOuterSemiJoin { - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: leftProfile.count, cardinality: make([]float64, p.schema.Len()), } @@ -301,7 +303,7 @@ func (p *LogicalJoin) deriveStats() (*statsInfo, error) { return p.stats, nil } if 0 == len(p.EqualConditions) { - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: leftProfile.count * rightProfile.count, cardinality: append(leftProfile.cardinality, rightProfile.cardinality...), } @@ -327,14 +329,14 @@ func (p *LogicalJoin) deriveStats() (*statsInfo, error) { for i := range cardinality { cardinality[i] = math.Min(cardinality[i], count) } - p.stats = &statsInfo{ + p.stats = &StatsInfo{ count: count, cardinality: cardinality, } return p.stats, nil } -func (la *LogicalApply) deriveStats() (*statsInfo, error) { +func (la *LogicalApply) deriveStats() (*StatsInfo, error) { leftProfile, err := la.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) @@ -343,7 +345,7 @@ func (la *LogicalApply) deriveStats() (*statsInfo, error) { if err != nil { return nil, errors.Trace(err) } - la.stats = &statsInfo{ + la.stats = &StatsInfo{ count: leftProfile.count, cardinality: make([]float64, la.schema.Len()), } @@ -359,8 +361,8 @@ func (la *LogicalApply) deriveStats() (*statsInfo, error) { } // Exists and MaxOneRow produce at most one row, so we set the count of stats one. -func getSingletonStats(len int) *statsInfo { - ret := &statsInfo{ +func getSingletonStats(len int) *StatsInfo { + ret := &StatsInfo{ count: 1.0, cardinality: make([]float64, len), } @@ -370,7 +372,7 @@ func getSingletonStats(len int) *statsInfo { return ret } -func (p *LogicalExists) deriveStats() (*statsInfo, error) { +func (p *LogicalExists) deriveStats() (*StatsInfo, error) { _, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err) @@ -379,7 +381,7 @@ func (p *LogicalExists) deriveStats() (*statsInfo, error) { return p.stats, nil } -func (p *LogicalMaxOneRow) deriveStats() (*statsInfo, error) { +func (p *LogicalMaxOneRow) deriveStats() (*StatsInfo, error) { _, err := p.children[0].deriveStats() if err != nil { return nil, errors.Trace(err)