From 42274d0c79160c6e0bdb8acea47ea85aa3b0e939 Mon Sep 17 00:00:00 2001 From: Yifan Xu <30385241+xuyifangreeneyes@users.noreply.github.com> Date: Thu, 2 Feb 2023 18:49:56 +0800 Subject: [PATCH] This is an automated cherry-pick of #38301 Signed-off-by: ti-chi-bot --- statistics/handle/update.go | 12 ++++++ statistics/handle/update_test.go | 63 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/statistics/handle/update.go b/statistics/handle/update.go index 1581b9872d90c..cb091f7c25390 100644 --- a/statistics/handle/update.go +++ b/statistics/handle/update.go @@ -475,7 +475,19 @@ func (h *Handle) dumpTableStatCountToKV(id int64, delta variable.TableDelta) (up if delta.Delta < 0 { _, err = exec.ExecuteInternal(ctx, "update mysql.stats_meta set version = %?, count = count - %?, modify_count = modify_count + %? where table_id = %? and count >= %?", startTS, -delta.Delta, delta.Count, id, -delta.Delta) } else { +<<<<<<< HEAD _, err = exec.ExecuteInternal(ctx, "update mysql.stats_meta set version = %?, count = count + %?, modify_count = modify_count + %? where table_id = %?", startTS, delta.Delta, delta.Count, id) +======= + if delta.Delta < 0 { + // use INSERT INTO ... ON DUPLICATE KEY UPDATE here to fill missing stats_meta. + _, err = exec.ExecuteInternal(ctx, "insert into mysql.stats_meta (version, table_id, modify_count, count) values (%?, %?, %?, 0) on duplicate key "+ + "update version = values(version), modify_count = modify_count + values(modify_count), count = if(count > %?, count - %?, 0)", startTS, id, delta.Count, -delta.Delta, -delta.Delta) + } else { + // use INSERT INTO ... ON DUPLICATE KEY UPDATE here to fill missing stats_meta. + _, err = exec.ExecuteInternal(ctx, "insert into mysql.stats_meta (version, table_id, modify_count, count) values (%?, %?, %?, %?) on duplicate key "+ + "update version = values(version), modify_count = modify_count + values(modify_count), count = count + values(count)", startTS, id, delta.Count, delta.Delta) + } +>>>>>>> 6e56bf717c (ddl, statistics: fix stats meta missing when creating many tables at once (#38301)) } return errors.Trace(err) } diff --git a/statistics/handle/update_test.go b/statistics/handle/update_test.go index fe4904e254be5..e98108d440805 100644 --- a/statistics/handle/update_test.go +++ b/statistics/handle/update_test.go @@ -1191,14 +1191,26 @@ func (s *testStatsSuite) TestOutOfOrderUpdate(c *C) { testKit.MustExec(fmt.Sprintf("update mysql.stats_meta set count = 1 where table_id = %d", tableInfo.ID)) testKit.MustExec("delete from t") +<<<<<<< HEAD c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil) testKit.MustQuery("select count from mysql.stats_meta").Check(testkit.Rows("1")) +======= + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + // If count < -Delta, then update count to 0. + // Check https://github.com/pingcap/tidb/pull/38301#discussion_r1094050951 for details. + testKit.MustQuery(fmt.Sprintf("select count from mysql.stats_meta where table_id = %d", tableInfo.ID)).Check(testkit.Rows("0")) +>>>>>>> 6e56bf717c (ddl, statistics: fix stats meta missing when creating many tables at once (#38301)) // Now another tidb has updated the delta info. testKit.MustExec(fmt.Sprintf("update mysql.stats_meta set count = 3 where table_id = %d", tableInfo.ID)) +<<<<<<< HEAD c.Assert(h.DumpStatsDeltaToKV(handle.DumpAll), IsNil) testKit.MustQuery("select count from mysql.stats_meta").Check(testkit.Rows("0")) +======= + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + testKit.MustQuery(fmt.Sprintf("select count from mysql.stats_meta where table_id = %d", tableInfo.ID)).Check(testkit.Rows("3")) +>>>>>>> 6e56bf717c (ddl, statistics: fix stats meta missing when creating many tables at once (#38301)) } func (s *testStatsSuite) TestUpdateStatsByLocalFeedback(c *C) { @@ -2334,3 +2346,54 @@ func (s *testSerialStatsSuite) TestAutoAnalyzeRatio(c *C) { c.Assert(h.Update(is), IsNil) c.Assert(h.HandleAutoAnalyze(s.do.InfoSchema()), IsTrue) } + +func TestFillMissingStatsMeta(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t1 (a int, b int)") + tk.MustExec("create table t2 (a int, b int) partition by range (a) (partition p0 values less than (10), partition p1 values less than (maxvalue))") + + tk.MustQuery("select * from mysql.stats_meta").Check(testkit.Rows()) + + is := dom.InfoSchema() + tbl1, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t1")) + require.NoError(t, err) + tbl1ID := tbl1.Meta().ID + tbl2, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t2")) + require.NoError(t, err) + tbl2Info := tbl2.Meta() + tbl2ID := tbl2Info.ID + require.Len(t, tbl2Info.Partition.Definitions, 2) + p0ID := tbl2Info.Partition.Definitions[0].ID + p1ID := tbl2Info.Partition.Definitions[1].ID + h := dom.StatsHandle() + + checkStatsMeta := func(id int64, expectedModifyCount, expectedCount string) int64 { + rows := tk.MustQuery(fmt.Sprintf("select version, modify_count, count from mysql.stats_meta where table_id = %v", id)).Rows() + require.Len(t, rows, 1) + ver, err := strconv.ParseInt(rows[0][0].(string), 10, 64) + require.NoError(t, err) + require.Equal(t, expectedModifyCount, rows[0][1]) + require.Equal(t, expectedCount, rows[0][2]) + return ver + } + + tk.MustExec("insert into t1 values (1, 2), (3, 4)") + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + ver1 := checkStatsMeta(tbl1ID, "2", "2") + tk.MustExec("delete from t1 where a = 1") + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + ver2 := checkStatsMeta(tbl1ID, "3", "1") + require.Greater(t, ver2, ver1) + + tk.MustExec("insert into t2 values (1, 2), (3, 4)") + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + checkStatsMeta(p0ID, "2", "2") + globalVer1 := checkStatsMeta(tbl2ID, "2", "2") + tk.MustExec("insert into t2 values (11, 12)") + require.NoError(t, h.DumpStatsDeltaToKV(handle.DumpAll)) + checkStatsMeta(p1ID, "1", "1") + globalVer2 := checkStatsMeta(tbl2ID, "3", "3") + require.Greater(t, globalVer2, globalVer1) +}