diff --git a/domain/historical_stats.go b/domain/historical_stats.go index 5d6d90feedef8..07e82bafeb58c 100644 --- a/domain/historical_stats.go +++ b/domain/historical_stats.go @@ -77,5 +77,10 @@ func (w *HistoricalStatsWorker) DumpHistoricalStats(tableID int64, statsHandle * // GetOneHistoricalStatsTable gets one tableID from channel, only used for test func (w *HistoricalStatsWorker) GetOneHistoricalStatsTable() int64 { - return <-w.tblCH + select { + case tblID := <-w.tblCH: + return tblID + default: + return -1 + } } diff --git a/executor/historical_stats_test.go b/executor/historical_stats_test.go index 6ae23dcebb365..0b00d3182f019 100644 --- a/executor/historical_stats_test.go +++ b/executor/historical_stats_test.go @@ -26,6 +26,7 @@ import ( "github.com/pingcap/tidb/statistics/handle" "github.com/pingcap/tidb/testkit" "github.com/stretchr/testify/require" + "github.com/tikv/client-go/v2/oracle" ) func TestRecordHistoryStatsAfterAnalyze(t *testing.T) { @@ -243,3 +244,65 @@ PARTITION p0 VALUES LESS THAN (6) require.NoError(t, err) tk.MustQuery("select count(*) from mysql.stats_history").Check(testkit.Rows("2")) } + +func TestDumpHistoricalStatsByTable(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("set global tidb_enable_historical_stats = 1") + tk.MustExec("set @@tidb_partition_prune_mode='static'") + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec(`CREATE TABLE t (a int, b int, index idx(b)) +PARTITION BY RANGE ( a ) ( +PARTITION p0 VALUES LESS THAN (6) +)`) + // dump historical stats + h := dom.StatsHandle() + + tk.MustExec("analyze table t") + is := dom.InfoSchema() + tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t")) + require.NoError(t, err) + require.NotNil(t, tbl) + + // dump historical stats + hsWorker := dom.GetHistoricalStatsWorker() + // only partition p0 stats will be dumped in static mode + tblID := hsWorker.GetOneHistoricalStatsTable() + require.NotEqual(t, tblID, -1) + err = hsWorker.DumpHistoricalStats(tblID, h) + require.NoError(t, err) + tblID = hsWorker.GetOneHistoricalStatsTable() + require.Equal(t, tblID, int64(-1)) + + time.Sleep(1 * time.Second) + snapshot := oracle.GoTimeToTS(time.Now()) + jsTable, err := h.DumpHistoricalStatsBySnapshot("test", tbl.Meta(), snapshot) + require.NoError(t, err) + require.NotNil(t, jsTable) + // only has p0 stats + require.NotNil(t, jsTable.Partitions["p0"]) + require.Nil(t, jsTable.Partitions["global"]) + + // change static to dynamic then assert + tk.MustExec("set @@tidb_partition_prune_mode='dynamic'") + tk.MustExec("analyze table t") + require.NoError(t, err) + // global and p0's stats will be dumped + tblID = hsWorker.GetOneHistoricalStatsTable() + require.NotEqual(t, tblID, -1) + err = hsWorker.DumpHistoricalStats(tblID, h) + require.NoError(t, err) + tblID = hsWorker.GetOneHistoricalStatsTable() + require.NotEqual(t, tblID, -1) + err = hsWorker.DumpHistoricalStats(tblID, h) + require.NoError(t, err) + time.Sleep(1 * time.Second) + snapshot = oracle.GoTimeToTS(time.Now()) + jsTable, err = h.DumpHistoricalStatsBySnapshot("test", tbl.Meta(), snapshot) + require.NoError(t, err) + require.NotNil(t, jsTable) + // has both global and p0 stats + require.NotNil(t, jsTable.Partitions["p0"]) + require.NotNil(t, jsTable.Partitions["global"]) +} diff --git a/statistics/handle/dump.go b/statistics/handle/dump.go index a83c6e57ee3c7..81e982881ee83 100644 --- a/statistics/handle/dump.go +++ b/statistics/handle/dump.go @@ -32,8 +32,10 @@ import ( "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/statistics" "github.com/pingcap/tidb/types" + "github.com/pingcap/tidb/util/logutil" "github.com/pingcap/tidb/util/sqlexec" "github.com/pingcap/tipb/go-tipb" + "go.uber.org/zap" ) // JSONTable is used for dumping statistics. @@ -173,9 +175,10 @@ func (h *Handle) DumpHistoricalStatsBySnapshot(dbName string, tableInfo *model.T if isDynamicMode { tbl, err := h.tableHistoricalStatsToJSON(tableInfo.ID, snapshot) if err != nil { - return nil, errors.Trace(err) - } - if tbl != nil { + logutil.BgLogger().Warn("dump global historical stats failed", + zap.Int64("table-id", tableInfo.ID), + zap.String("table-name", tableInfo.Name.String())) + } else if tbl != nil { jsonTbl.Partitions["global"] = tbl } }