diff --git a/statistics/handle/handle.go b/statistics/handle/handle.go index 3dc4977e94b32..5b7be3e3a2692 100644 --- a/statistics/handle/handle.go +++ b/statistics/handle/handle.go @@ -758,7 +758,7 @@ func (h *Handle) fmSketchFromStorage(reader *statsReader, tblID int64, isIndex, return statistics.DecodeFMSketch(rows[0].GetBytes(0)) } -func (h *Handle) indexStatsFromStorage(reader *statsReader, row chunk.Row, table *statistics.Table, tableInfo *model.TableInfo) error { +func (h *Handle) indexStatsFromStorage(reader *statsReader, row chunk.Row, table *statistics.Table, tableInfo *model.TableInfo, loadAll bool) error { histID := row.GetInt64(2) distinct := row.GetInt64(3) histVer := row.GetUint64(4) @@ -785,9 +785,14 @@ func (h *Handle) indexStatsFromStorage(reader *statsReader, row chunk.Row, table if err != nil { return errors.Trace(err) } - fmSketch, err := h.fmSketchFromStorage(reader, table.PhysicalID, 1, histID) - if err != nil { - return errors.Trace(err) + var fmSketch *statistics.FMSketch + if loadAll { + // FMSketch is only used when merging partition stats into global stats. When merging partition stats into global stats, + // we load all the statistics, i.e., loadAll is true. + fmSketch, err = h.fmSketchFromStorage(reader, table.PhysicalID, 1, histID) + if err != nil { + return errors.Trace(err) + } } idx = &statistics.Index{Histogram: *hg, CMSketch: cms, TopN: topN, FMSketch: fmSketch, Info: idxInfo, ErrorRate: errorRate, StatsVer: row.GetInt64(7), Flag: flag} lastAnalyzePos.Copy(&idx.LastAnalyzePos) @@ -948,7 +953,7 @@ func (h *Handle) TableStatsFromStorage(tableInfo *model.TableInfo, physicalID in } for _, row := range rows { if row.GetInt64(1) > 0 { - err = h.indexStatsFromStorage(reader, row, table, tableInfo) + err = h.indexStatsFromStorage(reader, row, table, tableInfo, loadAll) } else { err = h.columnStatsFromStorage(reader, row, table, tableInfo, loadAll) } diff --git a/statistics/integration_test.go b/statistics/integration_test.go index a0656f69a9cfc..3a858b1b22fcc 100644 --- a/statistics/integration_test.go +++ b/statistics/integration_test.go @@ -642,3 +642,28 @@ func TestCrossValidationSelectivity(t *testing.T) { "└─Selection 0.00 cop[tikv] gt(test.t.c, 1000)", " └─TableRangeScan 2.00 cop[tikv] table:t range:(1 0,1 1000), keep order:false")) } + +func TestUpdateNotLoadIndexFMSketch(t *testing.T) { + store, dom, clean := testkit.CreateMockStoreAndDomain(t) + defer clean() + tk := testkit.NewTestKit(t, store) + h := dom.StatsHandle() + tk.MustExec("use test") + tk.MustExec("create table t(a int, b int, index idx(a)) partition by range (a) (partition p0 values less than (10),partition p1 values less than maxvalue)") + tk.MustExec("insert into t values (1,2), (3,4), (5,6), (7,8)") + require.NoError(t, h.HandleDDLEvent(<-h.DDLEventCh())) + tk.MustExec("analyze table t") + is := dom.InfoSchema() + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + require.NoError(t, err) + tblInfo := tbl.Meta() + idxInfo := tblInfo.Indices[0] + p0 := tblInfo.Partition.Definitions[0] + p1 := tblInfo.Partition.Definitions[1] + require.Nil(t, h.GetPartitionStats(tblInfo, p0.ID).Indices[idxInfo.ID].FMSketch) + require.Nil(t, h.GetPartitionStats(tblInfo, p1.ID).Indices[idxInfo.ID].FMSketch) + h.Clear() + require.NoError(t, h.Update(is)) + require.Nil(t, h.GetPartitionStats(tblInfo, p0.ID).Indices[idxInfo.ID].FMSketch) + require.Nil(t, h.GetPartitionStats(tblInfo, p1.ID).Indices[idxInfo.ID].FMSketch) +}