Repository: pingcap/tidb
File: pkg/executor/test/analyzetest/memorycontrol/memory_control_test.go (Go)

Code before:
	tk.MustExec("create table tbl_2 ( col_20 decimal default 84232 , col_21 tinyint not null , col_22 int default 80814394 , col_23 mediumint default -8036687 not null , col_24 smallint default 9185 not null , col_25 tinyint unsigned default 65 , col_26 char(115) default 'ZyfroRODMbNDRZnPNRW' not null , col_27 bigint not null , col_28 tinyint not null , col_29 char(130) default 'UMApsVgzHblmY' , primary key idx_14 ( col_28,col_22 ) , unique key idx_15 ( col_24,col_22 ) , key idx_16 ( col_21,col_20,col_24,col_25,col_27,col_28,col_26,col_29 ) , key idx_17 ( col_24,col_25 ) , unique key idx_18 ( col_25,col_23,col_29,col_27,col_26,col_22 ) , key idx_19 ( col_25,col_22,col_26,col_23 ) , unique key idx_20 ( col_22,col_24,col_28,col_29,col_26,col_20 ) , key idx_21 ( col_25,col_24,col_26,col_29,col_27,col_22,col_28 ) );")
	tk.MustExec("insert ignore into tbl_2 values ( 942,33,-1915007317,3408149,-3699,193,'Trywdis',1876334369465184864,115,null );")
	tk.MustExec("set global tidb_mem_quota_analyze=128;")
	tk.MustExecToErr("analyze table tbl_2;")
}

func TestAnalyzeV2MemoryUsageMetricNeverNegative(t *testing.T) {
	store, _ := testkit.CreateMockStoreAndDomain(t)
	oldChildTrackers := executor.GlobalAnalyzeMemoryTracker.GetChildrenForTest()
	for _, tracker := range oldChildTrackers {
		tracker.Detach()
	}
	defer func() {
		for _, tracker := range oldChildTrackers {
			tracker.AttachTo(executor.GlobalAnalyzeMemoryTracker)
		}
	}()
	executor.GlobalAnalyzeMemoryTracker.ReplaceBytesUsed(0)

	tk := testkit.NewTestKit(t, store)
	tk.MustExec("set @@tidb_analyze_version=2")
	tk.MustExec("set @@tidb_build_sampling_stats_concurrency=1")
	tk.MustExec("use test")
	tk.MustExec("drop table if exists t_mem_usage")
	tk.MustExec("create table t_mem_usage(a text collate utf8mb4_general_ci)")
	tk.MustExec("insert into t_mem_usage values (repeat('a', 32000))")
	for range 11 {
		tk.MustExec("insert into t_mem_usage select a from t_mem_usage")
	}
	tk.MustExec("insert into t_mem_usage select a from t_mem_usage limit 952")

	tk.MustExec("analyze table t_mem_usage with 1.0 samplerate;")
}


Review comment (suggestion):
Analyze relies on the `MaxSampleValueLength` to skip big values when building stats.
Currently, this var is `32767`. But we may change it because other databases usually set this value to 1k or so.

So we can add an `intest.Assert(MaxSampleValueLength > 32000)` to ensure that the inserted values will affect the stats collection.

Code after:
	tk.MustExec("use test")
	tk.MustExec("create table tbl_2 ( col_20 decimal default 84232 , col_21 tinyint not null , col_22 int default 80814394 , col_23 mediumint default -8036687 not null , col_24 smallint default 9185 not null , col_25 tinyint unsigned default 65 , col_26 char(115) default 'ZyfroRODMbNDRZnPNRW' not null , col_27 bigint not null , col_28 tinyint not null , col_29 char(130) default 'UMApsVgzHblmY' , primary key idx_14 ( col_28,col_22 ) , unique key idx_15 ( col_24,col_22 ) , key idx_16 ( col_21,col_20,col_24,col_25,col_27,col_28,col_26,col_29 ) , key idx_17 ( col_24,col_25 ) , unique key idx_18 ( col_25,col_23,col_29,col_27,col_26,col_22 ) , key idx_19 ( col_25,col_22,col_26,col_23 ) , unique key idx_20 ( col_22,col_24,col_28,col_29,col_26,col_20 ) , key idx_21 ( col_25,col_24,col_26,col_29,col_27,col_22,col_28 ) );")
	tk.MustExec("insert ignore into tbl_2 values ( 942,33,-1915007317,3408149,-3699,193,'Trywdis',1876334369465184864,115,null );")
	tk.MustExec("set global tidb_mem_quota_analyze=128;")
	tk.MustExecToErr("analyze table tbl_2;")
}

func TestAnalyzeV2MemoryUsageMetricNeverNegative(t *testing.T) {
	// This test should be fast because the whole package is marked as `timeout = "short"` in Bazel.
	const valueLen = 8 * 1024
	intest.Assert(statistics.MaxSampleValueLength > valueLen)

	store, _ := testkit.CreateMockStoreAndDomain(t)
	oldChildTrackers := executor.GlobalAnalyzeMemoryTracker.GetChildrenForTest()
	for _, tracker := range oldChildTrackers {
		tracker.Detach()
	}
	defer func() {
		for _, tracker := range oldChildTrackers {
			tracker.AttachTo(executor.GlobalAnalyzeMemoryTracker)
		}
	}()
	executor.GlobalAnalyzeMemoryTracker.ReplaceBytesUsed(0)

	tk := testkit.NewTestKit(t, store)
	tk.MustExec("set @@tidb_analyze_version=2")
	tk.MustExec("set @@tidb_build_sampling_stats_concurrency=1")
	tk.MustExec("set @@tidb_analyze_skip_column_types = ''")
	tk.MustExec("use test")
	tk.MustExec("drop table if exists t_mem_usage")
	tk.MustExec("create table t_mem_usage(a text collate utf8mb4_general_ci)")
	tk.MustExec(fmt.Sprintf("insert into t_mem_usage values (repeat('a', %d))", valueLen))
	for range 6 {
		tk.MustExec("insert into t_mem_usage select a from t_mem_usage")
	}

	tk.MustExec("analyze table t_mem_usage with 1.0 samplerate;")
}

func TestAnalyzeSessionMemTrackerDetachOnClose(t *testing.T) {
	store := testkit.CreateMockStore(t)
	tk := testkit.NewTestKit(t, store)
	tk.MustExec("use test")

	err := tk.ExecToErr("analyze table test.not_exists with 1 topn")
	require.Error(t, err)

	vars := tk.Session().GetSessionVars()
	// Clear any residue from the analyze statement to make the delta deterministic.
	vars.MemTracker.ReplaceBytesUsed(0)
	base := executor.GlobalAnalyzeMemoryTracker.BytesConsumed()