diff --git a/expression/integration_test.go b/expression/integration_test.go index d4bd4781cf431..4e57b38f6bda9 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2620,8 +2620,8 @@ func (s *testIntegrationSuite) TestCompareBuiltin(c *C) { tk.MustExec("drop table if exists t;") tk.MustExec("create table t(a date)") result = tk.MustQuery("desc select a = a from t") - result.Check(testkit.Rows("TableScan_4 cop table:t, range:[-inf,+inf], keep order:false 8000", - "TableReader_5 Projection_3 root data:TableScan_4 8000", + result.Check(testkit.Rows("TableScan_4 cop table:t, range:[-inf,+inf], keep order:false 10000", + "TableReader_5 Projection_3 root data:TableScan_4 10000", "Projection_3 TableReader_5 root eq(test.t.a, test.t.a) 8000")) // for interval diff --git a/plan/cbo_test.go b/plan/cbo_test.go index 2f44c185b7a5a..be46c09ecb61a 100644 --- a/plan/cbo_test.go +++ b/plan/cbo_test.go @@ -386,9 +386,8 @@ func (s *testAnalyzeSuite) TestOutdatedAnalyze(c *C) { testKit.MustExec("insert into t select * from t") h.DumpStatsDeltaToKV() c.Assert(h.Update(dom.InfoSchema()), IsNil) - // FIXME: The count for table scan is wrong. testKit.MustQuery("explain select * from t where a <= 5 and b <= 5").Check(testkit.Rows( - "TableScan_5 Selection_6 cop table:t, range:[-inf,+inf], keep order:false 28.799999999999997", + "TableScan_5 Selection_6 cop table:t, range:[-inf,+inf], keep order:false 80", "Selection_6 TableScan_5 cop le(test.t.a, 5), le(test.t.b, 5) 28.799999999999997", "TableReader_7 root data:Selection_6 28.799999999999997", )) diff --git a/plan/logical_plans.go b/plan/logical_plans.go index 27ce77363ac82..cea86878d94b5 100644 --- a/plan/logical_plans.go +++ b/plan/logical_plans.go @@ -282,6 +282,9 @@ type DataSource struct { // pushedDownConds are the conditions that will be pushed down to coprocessor. pushedDownConds []expression.Expression + // statsAfterSelect is the statsInfo for dataSource and selection. + statsAfterSelect *statsInfo + statisticTable *statistics.Table // availableIndices is used for storing result of avalableIndices function. diff --git a/plan/physical_plan_builder.go b/plan/physical_plan_builder.go index 65ca4bf2375e2..6d9b7b1fe8f75 100644 --- a/plan/physical_plan_builder.go +++ b/plan/physical_plan_builder.go @@ -429,7 +429,7 @@ func (is *PhysicalIndexScan) addPushedDownSelection(copTask *copTask, p *DataSou } if tableConds != nil { copTask.finishIndexPlan() - tableSel := PhysicalSelection{Conditions: tableConds}.init(is.ctx, p.stats.scaleByExpectCnt(expectedCnt)) + tableSel := PhysicalSelection{Conditions: tableConds}.init(is.ctx, p.statsAfterSelect.scaleByExpectCnt(expectedCnt)) tableSel.SetChildren(copTask.tablePlan) copTask.tablePlan = tableSel copTask.cst += copTask.count() * cpuFactor @@ -586,7 +586,7 @@ func (ds *DataSource) convertToTableScan(prop *requiredProp) (task task, err err } ts.KeepOrder = true copTask.keepOrder = true - ts.addPushedDownSelection(copTask, ds.stats.scaleByExpectCnt(prop.expectedCnt)) + ts.addPushedDownSelection(copTask, ds.statsAfterSelect.scaleByExpectCnt(prop.expectedCnt)) } else { expectedCnt := math.MaxFloat64 if prop.isEmpty() { @@ -594,7 +594,7 @@ func (ds *DataSource) convertToTableScan(prop *requiredProp) (task task, err err } else { return invalidTask, nil } - ts.addPushedDownSelection(copTask, ds.stats.scaleByExpectCnt(expectedCnt)) + ts.addPushedDownSelection(copTask, ds.statsAfterSelect.scaleByExpectCnt(expectedCnt)) } if prop.taskTp == rootTaskType { task = finishCopTask(task, ds.ctx) diff --git a/plan/stats.go b/plan/stats.go index f746ffa2e2038..5e6ee8e844e85 100644 --- a/plan/stats.go +++ b/plan/stats.go @@ -92,6 +92,7 @@ func (ds *DataSource) getStatsByFilter(conds expression.CNFExprs) *statsInfo { profile.cardinality[i] = profile.count * distinctFactor } } + ds.stats = profile selectivity, err := ds.statisticTable.Selectivity(ds.ctx, conds) if err != nil { log.Warnf("An error happened: %v, we have to use the default selectivity", err.Error()) @@ -105,8 +106,8 @@ func (ds *DataSource) deriveStats() *statsInfo { for i, expr := range ds.pushedDownConds { ds.pushedDownConds[i] = expression.PushDownNot(expr, false, nil) } - ds.stats = ds.getStatsByFilter(ds.pushedDownConds) - return ds.stats + ds.statsAfterSelect = ds.getStatsByFilter(ds.pushedDownConds) + return ds.statsAfterSelect } func (p *LogicalSelection) deriveStats() *statsInfo {