diff --git a/pkg/statistics/handle/storage/json.go b/pkg/statistics/handle/storage/json.go index 020383efb3521..a174d38aaa566 100644 --- a/pkg/statistics/handle/storage/json.go +++ b/pkg/statistics/handle/storage/json.go @@ -18,6 +18,7 @@ import ( "bytes" "encoding/json" "io" + "sync/atomic" "time" "github.com/klauspost/compress/gzip" @@ -31,6 +32,7 @@ import ( "github.com/pingcap/tidb/pkg/types" compressutil "github.com/pingcap/tidb/pkg/util/compress" "github.com/pingcap/tidb/pkg/util/logutil" + "github.com/pingcap/tidb/pkg/util/memory" "go.uber.org/zap" ) @@ -88,7 +90,10 @@ func dumpJSONCol(hist *statistics.Histogram, cmsketch *statistics.CMSketch, topn } // GenJSONTableFromStats generate jsonTable from tableInfo and stats -func GenJSONTableFromStats(dbName string, tableInfo *model.TableInfo, tbl *statistics.Table) (*util.JSONTable, error) { +func GenJSONTableFromStats(sctx sessionctx.Context, dbName string, tableInfo *model.TableInfo, tbl *statistics.Table) (*util.JSONTable, error) { + tracker := memory.NewTracker(memory.LabelForAnalyzeMemory, -1) + tracker.AttachTo(sctx.GetSessionVars().MemTracker) + defer tracker.Detach() jsonTbl := &util.JSONTable{ DatabaseName: dbName, TableName: tableInfo.Name.L, @@ -104,11 +109,21 @@ func GenJSONTableFromStats(dbName string, tableInfo *model.TableInfo, tbl *stati if err != nil { return nil, errors.Trace(err) } - jsonTbl.Columns[col.Info.Name.L] = dumpJSONCol(hist, col.CMSketch, col.TopN, col.FMSketch, &col.StatsVer) + proto := dumpJSONCol(hist, col.CMSketch, col.TopN, col.FMSketch, &col.StatsVer) + tracker.Consume(proto.TotalMemoryUsage()) + if atomic.LoadUint32(&sctx.GetSessionVars().Killed) == 1 { + return nil, errors.Trace(statistics.ErrQueryInterrupted) + } + jsonTbl.Columns[col.Info.Name.L] = proto + col.FMSketch.DestroyAndPutToPool() } - for _, idx := range tbl.Indices { - jsonTbl.Indices[idx.Info.Name.L] = dumpJSONCol(&idx.Histogram, idx.CMSketch, idx.TopN, nil, &idx.StatsVer) + proto := dumpJSONCol(&idx.Histogram, idx.CMSketch, idx.TopN, nil, &idx.StatsVer) + tracker.Consume(proto.TotalMemoryUsage()) + if atomic.LoadUint32(&sctx.GetSessionVars().Killed) == 1 { + return nil, errors.Trace(statistics.ErrQueryInterrupted) + } + jsonTbl.Indices[idx.Info.Name.L] = proto } jsonTbl.ExtStats = dumpJSONExtendedStats(tbl.ExtendedStats) return jsonTbl, nil diff --git a/pkg/statistics/handle/storage/stats_read_writer.go b/pkg/statistics/handle/storage/stats_read_writer.go index 3c968224a6cfd..b35879bce7c4e 100644 --- a/pkg/statistics/handle/storage/stats_read_writer.go +++ b/pkg/statistics/handle/storage/stats_read_writer.go @@ -478,17 +478,18 @@ func (s *statsReadWriter) TableStatsToJSON(dbName string, tableInfo *model.Table if err != nil || tbl == nil { return nil, err } + var jsonTbl *util.JSONTable err = util.CallWithSCtx(s.statsHandler.SPool(), func(sctx sessionctx.Context) error { tbl.Version, tbl.ModifyCount, tbl.RealtimeCount, err = StatsMetaByTableIDFromStorage(sctx, physicalID, snapshot) + if err != nil { + return err + } + jsonTbl, err = GenJSONTableFromStats(sctx, dbName, tableInfo, tbl) return err }) if err != nil { return nil, err } - jsonTbl, err := GenJSONTableFromStats(dbName, tableInfo, tbl) - if err != nil { - return nil, err - } return jsonTbl, nil } diff --git a/pkg/statistics/handle/util/util.go b/pkg/statistics/handle/util/util.go index ef47f4451b2b4..5ed0da604c73c 100644 --- a/pkg/statistics/handle/util/util.go +++ b/pkg/statistics/handle/util/util.go @@ -280,3 +280,17 @@ type JSONColumn struct { LastUpdateVersion uint64 `json:"last_update_version"` Correlation float64 `json:"correlation"` } + +// TotalMemoryUsage returns the total memory usage of this column. +func (col *JSONColumn) TotalMemoryUsage() (size int64) { + if col.Histogram != nil { + size += int64(col.Histogram.Size()) + } + if col.CMSketch != nil { + size += int64(col.CMSketch.Size()) + } + if col.FMSketch != nil { + size += int64(col.FMSketch.Size()) + } + return size +}