diff --git a/pkg/sessionctx/variable/sysvar.go b/pkg/sessionctx/variable/sysvar.go index 190a275b8ff0c..6e1918ab1d2c3 100644 --- a/pkg/sessionctx/variable/sysvar.go +++ b/pkg/sessionctx/variable/sysvar.go @@ -723,7 +723,27 @@ var defaultSysVars = []*SysVar{ EnableLocalTxn.Store(newVal) return nil }}, - {Scope: ScopeGlobal, Name: TiDBAutoAnalyzeRatio, Value: strconv.FormatFloat(DefAutoAnalyzeRatio, 'f', -1, 64), Type: TypeFloat, MinValue: 0, MaxValue: math.MaxUint64}, + { + Scope: ScopeGlobal, + Name: TiDBAutoAnalyzeRatio, + Value: strconv.FormatFloat(DefAutoAnalyzeRatio, 'f', -1, 64), + Type: TypeFloat, + MinValue: 0, + MaxValue: math.MaxUint64, + // The value of TiDBAutoAnalyzeRatio should be greater than 0.00001 or equal to 0.00001. + Validation: func(vars *SessionVars, normalizedValue string, originalValue string, scope ScopeFlag) (string, error) { + ratio, err := strconv.ParseFloat(normalizedValue, 64) + if err != nil { + return "", err + } + const minRatio = 0.00001 + const tolerance = 1e-9 + if ratio < minRatio && math.Abs(ratio-minRatio) > tolerance { + return "", errors.Errorf("the value of %s should be greater than or equal to %f", TiDBAutoAnalyzeRatio, minRatio) + } + return normalizedValue, nil + }, + }, {Scope: ScopeGlobal, Name: TiDBAutoAnalyzeStartTime, Value: DefAutoAnalyzeStartTime, Type: TypeTime}, {Scope: ScopeGlobal, Name: TiDBAutoAnalyzeEndTime, Value: DefAutoAnalyzeEndTime, Type: TypeTime}, {Scope: ScopeGlobal, Name: TiDBMemQuotaBindingCache, Value: strconv.FormatInt(DefTiDBMemQuotaBindingCache, 10), Type: TypeUnsigned, MaxValue: math.MaxInt32, GetGlobal: func(_ context.Context, sv *SessionVars) (string, error) { diff --git a/pkg/sessionctx/variable/sysvar_test.go b/pkg/sessionctx/variable/sysvar_test.go index 06dbda61ddc89..e71dc91dd0bf8 100644 --- a/pkg/sessionctx/variable/sysvar_test.go +++ b/pkg/sessionctx/variable/sysvar_test.go @@ -1353,6 +1353,61 @@ func TestTiDBEnableRowLevelChecksum(t *testing.T) { require.Equal(t, Off, val) } +func TestTiDBAutoAnalyzeRatio(t *testing.T) { + ctx := context.Background() + vars := NewSessionVars(nil) + mock := NewMockGlobalAccessor4Tests() + mock.SessionVars = vars + vars.GlobalVarsAccessor = mock + + // default to 0.5 + val, err := mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "0.5", val) + + // set to 0.1 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "0.1") + require.NoError(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "0.1", val) + + // set to 1.1 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "1.1") + require.NoError(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "1.1", val) + + // set to 0 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "0") + require.Error(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "1.1", val) + + // set to 0.0000000001 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "0.0000000001") + require.Error(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "1.1", val) + + // set to 0.00001 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "0.00001") + require.NoError(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "0.00001", val) + + // set to 0.000009999 + err = mock.SetGlobalSysVar(ctx, TiDBAutoAnalyzeRatio, "0.000009999") + require.Error(t, err) + val, err = mock.GetGlobalSysVar(TiDBAutoAnalyzeRatio) + require.NoError(t, err) + require.Equal(t, "0.00001", val) +} + func TestTiDBTiFlashReplicaRead(t *testing.T) { vars := NewSessionVars(nil) mock := NewMockGlobalAccessor4Tests() diff --git a/pkg/statistics/handle/autoanalyze/autoanalyze_test.go b/pkg/statistics/handle/autoanalyze/autoanalyze_test.go index 3d95d0638cfff..2acfe70d5de11 100644 --- a/pkg/statistics/handle/autoanalyze/autoanalyze_test.go +++ b/pkg/statistics/handle/autoanalyze/autoanalyze_test.go @@ -103,8 +103,7 @@ func TestDisableAutoAnalyze(t *testing.T) { is := dom.InfoSchema() require.NoError(t, h.Update(is)) - // Set auto analyze ratio to 0. - tk.MustExec("set @@global.tidb_auto_analyze_ratio = 0") + tk.MustExec("set @@global.tidb_enable_auto_analyze = 0") exec.AutoAnalyzeMinCnt = 0 defer func() { exec.AutoAnalyzeMinCnt = 1000 diff --git a/pkg/statistics/handle/autoanalyze/refresher/refresher_test.go b/pkg/statistics/handle/autoanalyze/refresher/refresher_test.go index d5cdbaf8968b9..02ad638ec0646 100644 --- a/pkg/statistics/handle/autoanalyze/refresher/refresher_test.go +++ b/pkg/statistics/handle/autoanalyze/refresher/refresher_test.go @@ -54,8 +54,10 @@ func TestSkipAnalyzeTableWhenAutoAnalyzeRatioIsZero(t *testing.T) { ) tk.MustExec("insert into t1 values (1, 1), (2, 2), (3, 3)") tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3)") - // Set the auto analyze ratio to 0. - tk.MustExec("set global tidb_auto_analyze_ratio = 0") + // HACK: Set the auto analyze ratio to 0. + // We don't allow users to set the ratio to 0 anymore, but we still need to test this case. + // Because we need to compilable with the old configuration. + tk.MustExec("update mysql.global_variables set variable_value = '0' where variable_name = 'tidb_auto_analyze_ratio'") handle := dom.StatsHandle() require.NoError(t, handle.DumpStatsDeltaToKV(true)) require.NoError(t, handle.Update(dom.InfoSchema())) diff --git a/pkg/statistics/handle/updatetest/update_test.go b/pkg/statistics/handle/updatetest/update_test.go index ed49d794a01b9..5d01f0aa4a1c2 100644 --- a/pkg/statistics/handle/updatetest/update_test.go +++ b/pkg/statistics/handle/updatetest/update_test.go @@ -368,7 +368,7 @@ func TestAutoUpdate(t *testing.T) { testKit.MustExec("set global tidb_auto_analyze_ratio = 0.2") defer func() { exec.AutoAnalyzeMinCnt = 1000 - testKit.MustExec("set global tidb_auto_analyze_ratio = 0.0") + testKit.MustExec("set global tidb_auto_analyze_ratio = 0.5") }() do := dom @@ -473,7 +473,7 @@ func TestAutoUpdatePartition(t *testing.T) { testKit.MustExec("set global tidb_auto_analyze_ratio = 0.6") defer func() { exec.AutoAnalyzeMinCnt = 1000 - testKit.MustExec("set global tidb_auto_analyze_ratio = 0.0") + testKit.MustExec("set global tidb_auto_analyze_ratio = 0.5") }() do := dom @@ -806,7 +806,7 @@ func TestAutoUpdatePartitionInDynamicOnlyMode(t *testing.T) { testKit.MustExec("set global tidb_auto_analyze_ratio = 0.1") defer func() { exec.AutoAnalyzeMinCnt = 1000 - testKit.MustExec("set global tidb_auto_analyze_ratio = 0.0") + testKit.MustExec("set global tidb_auto_analyze_ratio = 0.5") }() require.NoError(t, h.Update(is))