Skip to content

Commit

Permalink
statistics: fix a case that auto-analyze is triggered outside its tim…
Browse files Browse the repository at this point in the history
…e range (#23214) (#23219)
  • Loading branch information
ti-srebot authored Mar 11, 2021
1 parent 51158bd commit 122ee4d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 6 deletions.
19 changes: 13 additions & 6 deletions statistics/handle/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,11 @@ func TableAnalyzed(tbl *statistics.Table) bool {
// "tbl.ModifyCount/tbl.Count > autoAnalyzeRatio" and the current time is
// between `start` and `end`.
func NeedAnalyzeTable(tbl *statistics.Table, limit time.Duration, autoAnalyzeRatio float64, start, end, now time.Time) (bool, string) {
// Tests if current time is within the time period.
if !timeutil.WithinDayTimePeriod(start, end, now) {
return false, ""
}

analyzed := TableAnalyzed(tbl)
if !analyzed {
t := time.Unix(0, oracle.ExtractPhysical(tbl.Version)*int64(time.Millisecond))
Expand All @@ -685,8 +690,7 @@ func NeedAnalyzeTable(tbl *statistics.Table, limit time.Duration, autoAnalyzeRat
if float64(tbl.ModifyCount)/float64(tbl.Count) <= autoAnalyzeRatio {
return false, ""
}
// Tests if current time is within the time period.
return timeutil.WithinDayTimePeriod(start, end, now), fmt.Sprintf("too many modifications(%v/%v>%v)", tbl.ModifyCount, tbl.Count, autoAnalyzeRatio)
return true, fmt.Sprintf("too many modifications(%v/%v>%v)", tbl.ModifyCount, tbl.Count, autoAnalyzeRatio)
}

func (h *Handle) getAutoAnalyzeParameters() map[string]string {
Expand Down Expand Up @@ -727,14 +731,14 @@ func parseAnalyzePeriod(start, end string) (time.Time, time.Time, error) {
}

// HandleAutoAnalyze analyzes the newly created table or index.
func (h *Handle) HandleAutoAnalyze(is infoschema.InfoSchema) {
func (h *Handle) HandleAutoAnalyze(is infoschema.InfoSchema) (analyzed bool) {
dbs := is.AllSchemaNames()
parameters := h.getAutoAnalyzeParameters()
autoAnalyzeRatio := parseAutoAnalyzeRatio(parameters[variable.TiDBAutoAnalyzeRatio])
start, end, err := parseAnalyzePeriod(parameters[variable.TiDBAutoAnalyzeStartTime], parameters[variable.TiDBAutoAnalyzeEndTime])
if err != nil {
logutil.BgLogger().Error("[stats] parse auto analyze period failed", zap.Error(err))
return
return false
}
for _, db := range dbs {
tbls := is.SchemaTables(model.NewCIStr(db))
Expand All @@ -747,7 +751,9 @@ func (h *Handle) HandleAutoAnalyze(is infoschema.InfoSchema) {
sql := fmt.Sprintf("analyze table %s", tblName)
analyzed := h.autoAnalyzeTable(tblInfo, statsTbl, start, end, autoAnalyzeRatio, sql)
if analyzed {
return
// analyze one table at a time to let it get the freshest parameters.
// others will be analyzed next round which is just 3s later.
return true
}
continue
}
Expand All @@ -756,12 +762,13 @@ func (h *Handle) HandleAutoAnalyze(is infoschema.InfoSchema) {
statsTbl := h.GetPartitionStats(tblInfo, def.ID)
analyzed := h.autoAnalyzeTable(tblInfo, statsTbl, start, end, autoAnalyzeRatio, sql)
if analyzed {
return
return true
}
continue
}
}
}
return false
}

func (h *Handle) autoAnalyzeTable(tblInfo *model.TableInfo, statsTbl *statistics.Table, start, end time.Time, ratio float64, sql string) bool {
Expand Down
55 changes: 55 additions & 0 deletions statistics/handle/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ import (
)

var _ = Suite(&testStatsSuite{})
var _ = SerialSuites(&testSerialStatsSuite{})

type testSerialStatsSuite struct {
store kv.Storage
do *domain.Domain
}

func (s *testSerialStatsSuite) SetUpSuite(c *C) {
testleak.BeforeTest()
// Add the hook here to avoid data race.
var err error
s.store, s.do, err = newStoreWithBootstrap()
c.Assert(err, IsNil)
}

func (s *testSerialStatsSuite) TearDownSuite(c *C) {
s.do.Close()
s.store.Close()
testleak.AfterTest(c)()
}

type testStatsSuite struct {
store kv.Storage
Expand Down Expand Up @@ -465,6 +485,41 @@ func (s *testStatsSuite) TestAutoUpdate(c *C) {
c.Assert(hg.Len(), Equals, 3)
}

func (s *testSerialStatsSuite) TestAutoAnalyzeOnEmptyTable(c *C) {
defer cleanEnv(c, s.store, s.do)
tk := testkit.NewTestKit(c, s.store)

oriStart := tk.MustQuery("select @@tidb_auto_analyze_start_time").Rows()[0][0].(string)
oriEnd := tk.MustQuery("select @@tidb_auto_analyze_end_time").Rows()[0][0].(string)
defer func() {
tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_start_time='%v'", oriStart))
tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_end_time='%v'", oriEnd))
}()

t := time.Now().Add(-1 * time.Minute)
h, m := t.Hour(), t.Minute()
start, end := fmt.Sprintf("%02d:%02d +0000", h, m), fmt.Sprintf("%02d:%02d +0000", h, m)
tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_start_time='%v'", start))
tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_end_time='%v'", end))
s.do.StatsHandle().HandleAutoAnalyze(s.do.InfoSchema())

tk.MustExec("use test")
tk.MustExec("create table t (a int, index idx(a))")
// to pass the stats.Pseudo check in autoAnalyzeTable
tk.MustExec("analyze table t")
// to pass the AutoAnalyzeMinCnt check in autoAnalyzeTable
tk.MustExec("insert into t values (1)" + strings.Repeat(", (1)", int(handle.AutoAnalyzeMinCnt)))
c.Assert(s.do.StatsHandle().DumpStatsDeltaToKV(handle.DumpAll), IsNil)
c.Assert(s.do.StatsHandle().Update(s.do.InfoSchema()), IsNil)

// test if it will be limited by the time range
c.Assert(s.do.StatsHandle().HandleAutoAnalyze(s.do.InfoSchema()), IsFalse)

tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_start_time='00:00 +0000'"))
tk.MustExec(fmt.Sprintf("set global tidb_auto_analyze_end_time='23:59 +0000'"))
c.Assert(s.do.StatsHandle().HandleAutoAnalyze(s.do.InfoSchema()), IsTrue)
}

func (s *testStatsSuite) TestAutoUpdatePartition(c *C) {
defer cleanEnv(c, s.store, s.do)
testKit := testkit.NewTestKit(c, s.store)
Expand Down

0 comments on commit 122ee4d

Please sign in to comment.