diff --git a/executor/analyze.go b/executor/analyze.go index 889c00297b4b4..c62404331c22c 100644 --- a/executor/analyze.go +++ b/executor/analyze.go @@ -596,6 +596,10 @@ func analyzeColumnsPushdown(colExec *AnalyzeColumnsExec) *statistics.AnalyzeResu } } idxNDVPushDownCh := make(chan analyzeIndexNDVTotalResult, 1) + // subIndexWorkerWg is better to be initialized in handleNDVForSpecialIndexes, however if we do so, golang would + // report unexpected/unreasonable data race error on subIndexWorkerWg when running TestAnalyzeVirtualCol test + // case with `-race` flag now. + colExec.subIndexWorkerWg = &sync.WaitGroup{} go colExec.handleNDVForSpecialIndexes(specialIndexes, idxNDVPushDownCh) count, hists, topns, fmSketches, extStats, err := colExec.buildSamplingStats(ranges, collExtStats, specialIndexesOffsets, idxNDVPushDownCh) if err != nil { @@ -1008,7 +1012,6 @@ func (e *AnalyzeColumnsExec) handleNDVForSpecialIndexes(indexInfos []*model.Inde statistics.AddNewAnalyzeJob(task.job) } resultsCh := make(chan *statistics.AnalyzeResults, len(tasks)) - e.subIndexWorkerWg = &sync.WaitGroup{} e.subIndexWorkerWg.Add(statsConcurrncy) for i := 0; i < statsConcurrncy; i++ { go e.subIndexWorkerForNDV(taskCh, resultsCh, i == 0) diff --git a/statistics/handle/handle.go b/statistics/handle/handle.go index 9bd279d9539f5..bbd500e8e7c38 100644 --- a/statistics/handle/handle.go +++ b/statistics/handle/handle.go @@ -1001,6 +1001,10 @@ func (h *Handle) SaveTableStatsToStorage(results *statistics.AnalyzeResults, nee // 2. Save histograms. for _, result := range results.Ars { for i, hg := range result.Hist { + // It's normal virtual column, skip it. + if hg == nil { + continue + } var cms *statistics.CMSketch if results.StatsVer != statistics.Version2 { cms = result.Cms[i] diff --git a/statistics/handle/handle_test.go b/statistics/handle/handle_test.go index ab00916ad1b11..001bacac3e4a5 100644 --- a/statistics/handle/handle_test.go +++ b/statistics/handle/handle_test.go @@ -759,6 +759,18 @@ func (s *testStatsSuite) TestCorrelation(c *C) { c.Assert(result.Rows()[0][9], Equals, "0") } +func (s *testStatsSuite) TestAnalyzeVirtualCol(c *C) { + defer cleanEnv(c, s.store, s.do) + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int, b int generated always as (-a) virtual, c int generated always as (-a) stored, index (c))") + tk.MustExec("insert into t(a) values(2),(1),(1),(3),(NULL)") + tk.MustExec("set @@tidb_analyze_version = 2") + tk.MustExec("analyze table t") + c.Assert(len(tk.MustQuery("show stats_histograms where table_name ='t'").Rows()), Equals, 3) +} + func (s *testStatsSuite) TestShowGlobalStats(c *C) { defer cleanEnv(c, s.store, s.do) tk := testkit.NewTestKit(c, s.store)