Skip to content

Commit 8299b27

Browse files
authored
statistics/handle: refine the condition of dumping stats delta (#41133) (#41168)
ref #36004, ref #38189, ref #39785
1 parent 0882912 commit 8299b27

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

statistics/handle/update.go

+28-9
Original file line numberDiff line numberDiff line change
@@ -403,22 +403,35 @@ var (
403403
dumpStatsMaxDuration = time.Hour
404404
)
405405

406-
// needDumpStatsDelta returns true when only updates a small portion of the table and the time since last update
407-
// do not exceed one hour.
408-
func needDumpStatsDelta(h *Handle, id int64, item variable.TableDelta, currentTime time.Time) bool {
409-
if item.InitTime.IsZero() {
410-
item.InitTime = currentTime
406+
// needDumpStatsDelta checks whether to dump stats delta.
407+
// 1. If the table doesn't exist or is a mem table or system table, then return false.
408+
// 2. If the mode is DumpAll, then return true.
409+
// 3. If the stats delta haven't been dumped in the past hour, then return true.
410+
// 4. If the table stats is pseudo or empty or `Modify Count / Table Count` exceeds the threshold.
411+
func (h *Handle) needDumpStatsDelta(is infoschema.InfoSchema, mode dumpMode, id int64, item variable.TableDelta, currentTime time.Time) bool {
412+
tbl, ok := h.getTableByPhysicalID(is, id)
413+
if !ok {
414+
return false
411415
}
412-
tbl, ok := h.statsCache.Load().(statsCache).Get(id)
416+
dbInfo, ok := is.SchemaByTable(tbl.Meta())
413417
if !ok {
414-
// No need to dump if the stats is invalid.
415418
return false
416419
}
420+
if util.IsMemOrSysDB(dbInfo.Name.L) {
421+
return false
422+
}
423+
if mode == DumpAll {
424+
return true
425+
}
426+
if item.InitTime.IsZero() {
427+
item.InitTime = currentTime
428+
}
417429
if currentTime.Sub(item.InitTime) > dumpStatsMaxDuration {
418430
// Dump the stats to kv at least once an hour.
419431
return true
420432
}
421-
if tbl.Count == 0 || float64(item.Count)/float64(tbl.Count) > DumpStatsDeltaRatio {
433+
statsTbl := h.GetPartitionStats(tbl.Meta(), id)
434+
if statsTbl.Pseudo || statsTbl.Count == 0 || float64(item.Count)/float64(statsTbl.Count) > DumpStatsDeltaRatio {
422435
// Dump the stats when there are many modifications.
423436
return true
424437
}
@@ -487,9 +500,15 @@ func (h *Handle) DumpStatsDeltaToKV(mode dumpMode) error {
487500
h.globalMap.data = deltaMap
488501
h.globalMap.Unlock()
489502
}()
503+
// TODO: pass in do.InfoSchema() to DumpStatsDeltaToKV.
504+
is := func() infoschema.InfoSchema {
505+
h.mu.Lock()
506+
defer h.mu.Unlock()
507+
return h.mu.ctx.GetDomainInfoSchema().(infoschema.InfoSchema)
508+
}()
490509
currentTime := time.Now()
491510
for id, item := range deltaMap {
492-
if mode == DumpDelta && !needDumpStatsDelta(h, id, item, currentTime) {
511+
if !h.needDumpStatsDelta(is, mode, id, item, currentTime) {
493512
continue
494513
}
495514
updated, err := h.dumpTableStatCountToKV(id, item)

statistics/handle/update_test.go

+26-4
Original file line numberDiff line numberDiff line change
@@ -2691,20 +2691,42 @@ func TestFillMissingStatsMeta(t *testing.T) {
26912691
}
26922692

26932693
tk.MustExec("insert into t1 values (1, 2), (3, 4)")
2694-
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll))
2694+
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpDelta))
2695+
require.NoError(t, h.Update(is))
26952696
ver1 := checkStatsMeta(tbl1ID, "2", "2")
26962697
tk.MustExec("delete from t1 where a = 1")
2697-
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll))
2698+
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpDelta))
2699+
require.NoError(t, h.Update(is))
26982700
ver2 := checkStatsMeta(tbl1ID, "3", "1")
26992701
require.Greater(t, ver2, ver1)
27002702

27012703
tk.MustExec("insert into t2 values (1, 2), (3, 4)")
2702-
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll))
2704+
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpDelta))
2705+
require.NoError(t, h.Update(is))
27032706
checkStatsMeta(p0ID, "2", "2")
27042707
globalVer1 := checkStatsMeta(tbl2ID, "2", "2")
27052708
tk.MustExec("insert into t2 values (11, 12)")
2706-
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll))
2709+
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpDelta))
2710+
require.NoError(t, h.Update(is))
27072711
checkStatsMeta(p1ID, "1", "1")
27082712
globalVer2 := checkStatsMeta(tbl2ID, "3", "3")
27092713
require.Greater(t, globalVer2, globalVer1)
27102714
}
2715+
2716+
func TestNotDumpSysTable(t *testing.T) {
2717+
store, dom := testkit.CreateMockStoreAndDomain(t)
2718+
tk := testkit.NewTestKit(t, store)
2719+
tk.MustExec("use test")
2720+
tk.MustExec("create table t1 (a int, b int)")
2721+
h := dom.StatsHandle()
2722+
require.NoError(t, h.HandleDDLEvent(<-h.DDLEventCh()))
2723+
tk.MustQuery("select count(1) from mysql.stats_meta").Check(testkit.Rows("1"))
2724+
// After executing `delete from mysql.stats_meta`, a delta for mysql.stats_meta is created but it would not be dumped.
2725+
tk.MustExec("delete from mysql.stats_meta")
2726+
require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll))
2727+
is := dom.InfoSchema()
2728+
tbl, err := is.TableByName(model.NewCIStr("mysql"), model.NewCIStr("stats_meta"))
2729+
require.NoError(t, err)
2730+
tblID := tbl.Meta().ID
2731+
tk.MustQuery(fmt.Sprintf("select * from mysql.stats_meta where table_id = %v", tblID)).Check(testkit.Rows())
2732+
}

0 commit comments

Comments
 (0)