diff --git a/config/config.go b/config/config.go index bc7ecedd073a6..f8248398f64cb 100644 --- a/config/config.go +++ b/config/config.go @@ -176,6 +176,7 @@ type Performance struct { TCPKeepAlive bool `toml:"tcp-keep-alive" json:"tcp-keep-alive"` CrossJoin bool `toml:"cross-join" json:"cross-join"` StatsLease string `toml:"stats-lease" json:"stats-lease"` + EnableUpdateStats bool `toml:"enable-update-stats" json:"enable-update-stats"` RunAutoAnalyze bool `toml:"run-auto-analyze" json:"run-auto-analyze"` StmtCountLimit uint `toml:"stmt-count-limit" json:"stmt-count-limit"` FeedbackProbability float64 `toml:"feedback-probability" json:"feedback-probability"` @@ -321,6 +322,7 @@ var defaultConf = Config{ TCPKeepAlive: true, CrossJoin: true, StatsLease: "3s", + EnableUpdateStats: true, RunAutoAnalyze: true, StmtCountLimit: 5000, FeedbackProbability: 0.05, diff --git a/config/config.toml.example b/config/config.toml.example index a1c236d5a1d3c..8c04c46cde3ca 100644 --- a/config/config.toml.example +++ b/config/config.toml.example @@ -143,6 +143,9 @@ cross-join = true # Stats lease duration, which influences the time of analyze and stats load. stats-lease = "3s" +# Whether run stats updates on this tidb-server. It will use the value of `stats-lease` to set its tickers' values, so it won't work when `stats-lease` is zero. +enable-update-stats = true + # Run auto analyze worker on this tidb-server. run-auto-analyze = true diff --git a/domain/domain.go b/domain/domain.go index dfc91dbf622f5..1f779350d500e 100644 --- a/domain/domain.go +++ b/domain/domain.go @@ -837,6 +837,11 @@ func (do *Domain) UpdateTableStatsLoop(ctx sessionctx.Context) error { if do.statsLease <= 0 { return nil } + do.wg.Add(1) + go do.loadStatsWorker() + if !config.GetGlobalConfig().Performance.EnableUpdateStats { + return nil + } owner := do.newStatsOwner() do.wg.Add(1) do.SetStatsUpdating(true) @@ -865,22 +870,12 @@ func (do *Domain) newStatsOwner() owner.Manager { return statsOwner } -func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager) { - defer recoverInDomain("updateStatsWorker", false) +func (do *Domain) loadStatsWorker() { + defer recoverInDomain("loadStatsWorker", false) + defer do.wg.Done() lease := do.statsLease - deltaUpdateDuration := lease * 20 loadTicker := time.NewTicker(lease) defer loadTicker.Stop() - deltaUpdateTicker := time.NewTicker(deltaUpdateDuration) - defer deltaUpdateTicker.Stop() - loadHistogramTicker := time.NewTicker(lease) - defer loadHistogramTicker.Stop() - gcStatsTicker := time.NewTicker(100 * lease) - defer gcStatsTicker.Stop() - dumpFeedbackTicker := time.NewTicker(200 * lease) - defer dumpFeedbackTicker.Stop() - loadFeedbackTicker := time.NewTicker(5 * lease) - defer loadFeedbackTicker.Stop() statsHandle := do.StatsHandle() t := time.Now() err := statsHandle.InitStats(do.InfoSchema()) @@ -889,10 +884,6 @@ func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager) } else { logutil.Logger(context.Background()).Info("init stats info time", zap.Duration("take time", time.Since(t))) } - defer func() { - do.SetStatsUpdating(false) - do.wg.Done() - }() for { select { case <-loadTicker.C: @@ -900,37 +891,60 @@ func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager) if err != nil { logutil.Logger(context.Background()).Debug("update stats info failed", zap.Error(err)) } + err = statsHandle.LoadNeededHistograms() + if err != nil { + logutil.Logger(context.Background()).Debug("load histograms failed", zap.Error(err)) + } + case <-do.exit: + return + } + } +} + +func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager) { + defer recoverInDomain("updateStatsWorker", false) + lease := do.statsLease + deltaUpdateTicker := time.NewTicker(20 * lease) + defer deltaUpdateTicker.Stop() + gcStatsTicker := time.NewTicker(100 * lease) + defer gcStatsTicker.Stop() + dumpFeedbackTicker := time.NewTicker(200 * lease) + defer dumpFeedbackTicker.Stop() + loadFeedbackTicker := time.NewTicker(5 * lease) + defer loadFeedbackTicker.Stop() + statsHandle := do.StatsHandle() + defer func() { + do.SetStatsUpdating(false) + do.wg.Done() + }() + for { + select { case <-do.exit: statsHandle.FlushStats() return // This channel is sent only by ddl owner. case t := <-statsHandle.DDLEventCh(): - err = statsHandle.HandleDDLEvent(t) + err := statsHandle.HandleDDLEvent(t) if err != nil { logutil.Logger(context.Background()).Debug("handle ddl event failed", zap.Error(err)) } case <-deltaUpdateTicker.C: - err = statsHandle.DumpStatsDeltaToKV(statistics.DumpDelta) + err := statsHandle.DumpStatsDeltaToKV(statistics.DumpDelta) if err != nil { logutil.Logger(context.Background()).Debug("dump stats delta failed", zap.Error(err)) } statsHandle.UpdateErrorRate(do.InfoSchema()) - case <-loadHistogramTicker.C: - err = statsHandle.LoadNeededHistograms() - if err != nil { - logutil.Logger(context.Background()).Debug("load histograms failed", zap.Error(err)) - } case <-loadFeedbackTicker.C: statsHandle.UpdateStatsByLocalFeedback(do.InfoSchema()) if !owner.IsOwner() { continue } - err = statsHandle.HandleUpdateStats(do.InfoSchema()) + err := statsHandle.HandleUpdateStats(do.InfoSchema()) if err != nil { logutil.Logger(context.Background()).Debug("update stats using feedback failed", zap.Error(err)) } case <-dumpFeedbackTicker.C: - err = statsHandle.DumpStatsFeedbackToKV() + err := statsHandle.DumpStatsFeedbackToKV() if err != nil { logutil.Logger(context.Background()).Debug("dump stats feedback failed", zap.Error(err)) } @@ -938,7 +952,7 @@ func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager) if !owner.IsOwner() { continue } - err = statsHandle.GCStats(do.InfoSchema(), do.DDL().GetLease()) + err := statsHandle.GCStats(do.InfoSchema(), do.DDL().GetLease()) if err != nil { logutil.Logger(context.Background()).Debug("GC stats failed", zap.Error(err)) }