diff --git a/statistics/handle/handle.go b/statistics/handle/handle.go index 6d12067f8e2a8..837e962ee8320 100644 --- a/statistics/handle/handle.go +++ b/statistics/handle/handle.go @@ -266,6 +266,9 @@ func (h *Handle) Update(is infoschema.InfoSchema) error { continue } tableInfo := table.Meta() + if oldTbl, ok := oldCache.tables[physicalID]; ok && oldTbl.Version >= version && tableInfo.UpdateTS == oldTbl.TblInfoUpdateTS { + continue + } tbl, err := h.TableStatsFromStorage(tableInfo, physicalID, false, 0) // Error is not nil may mean that there are some ddl changes on this table, we will not update it. if err != nil { @@ -280,6 +283,7 @@ func (h *Handle) Update(is infoschema.InfoSchema) error { tbl.Count = count tbl.ModifyCount = modifyCount tbl.Name = getFullTableName(is, tableInfo) + tbl.TblInfoUpdateTS = tableInfo.UpdateTS tables = append(tables, tbl) } h.updateStatsCache(oldCache.update(tables, deletedTableIDs, lastVersion)) diff --git a/statistics/handle/handle_test.go b/statistics/handle/handle_test.go index fababfaa58a76..7bc489c120389 100644 --- a/statistics/handle/handle_test.go +++ b/statistics/handle/handle_test.go @@ -2133,3 +2133,24 @@ func (s *testStatsSuite) TestDuplicateFMSketch(c *C) { c.Assert(s.do.StatsHandle().GCStats(s.do.InfoSchema(), time.Duration(0)), IsNil) tk.MustQuery("select count(*) from mysql.stats_fm_sketch").Check(testkit.Rows("2")) } + +func (s *testStatsSuite) TestStatsCacheUpdateSkip(c *C) { + defer cleanEnv(c, s.store, s.do) + testKit := testkit.NewTestKit(c, s.store) + do := s.do + h := do.StatsHandle() + testKit.MustExec("use test") + testKit.MustExec("create table t (c1 int, c2 int)") + testKit.MustExec("insert into t values(1, 2)") + c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil) + testKit.MustExec("analyze table t") + is := do.InfoSchema() + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + c.Assert(err, IsNil) + tableInfo := tbl.Meta() + statsTbl1 := h.GetTableStats(tableInfo) + c.Assert(statsTbl1.Pseudo, IsFalse) + h.Update(is) + statsTbl2 := h.GetTableStats(tableInfo) + c.Assert(statsTbl1, Equals, statsTbl2) +} diff --git a/statistics/table.go b/statistics/table.go index 69a71ee44801e..3c6f186b98344 100644 --- a/statistics/table.go +++ b/statistics/table.go @@ -62,6 +62,12 @@ type Table struct { Version uint64 Name string ExtendedStats *ExtendedStatsColl + // TblInfoUpdateTS is the UpdateTS of the TableInfo used when filling this struct. + // It is the schema version of the corresponding table. It is used to skip redundant + // loading of stats, i.e, if the cached stats is already update-to-date with mysql.stats_xxx tables, + // and the schema of the table does not change, we don't need to load the stats for this + // table again. + TblInfoUpdateTS uint64 } // ExtendedStatsItem is the cached item of a mysql.stats_extended record. @@ -136,9 +142,10 @@ func (t *Table) Copy() *Table { newHistColl.Indices[id] = idx } nt := &Table{ - HistColl: newHistColl, - Version: t.Version, - Name: t.Name, + HistColl: newHistColl, + Version: t.Version, + Name: t.Name, + TblInfoUpdateTS: t.TblInfoUpdateTS, } if t.ExtendedStats != nil { newExtStatsColl := &ExtendedStatsColl{