Skip to content

Commit

Permalink
*: add a new variable to control whether to invalidate plan cache whe…
Browse files Browse the repository at this point in the history
…n related table analyzed (#43390)

close #43295
  • Loading branch information
time-and-fate authored Apr 25, 2023
1 parent 853c320 commit 0b8f880
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 3 deletions.
4 changes: 3 additions & 1 deletion planner/core/plan_cache_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,9 @@ func (l *LRUPlanCache) pickFromBucket(bucket map[*list.Element]struct{}, matchOp
continue
}
// table stats has changed
if plan.matchOpts.StatsVersionHash != matchOpts.StatsVersionHash {
// this check can be disabled by turning off system variable tidb_plan_cache_invalidation_on_fresh_stats
if l.sctx.GetSessionVars().PlanCacheInvalidationOnFreshStats &&
plan.matchOpts.StatsVersionHash != matchOpts.StatsVersionHash {
continue
}

Expand Down
6 changes: 5 additions & 1 deletion planner/core/plan_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,11 @@ func TestPreparedPlanCacheStats(t *testing.T) {
tk.MustExec(`execute st using @a`)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustExec("analyze table t")
tk.MustExec(`execute st using @a`) // stats changes can affect prep cache hit
tk.MustExec("set tidb_plan_cache_invalidation_on_fresh_stats = 0")
tk.MustExec(`execute st using @a`)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
tk.MustExec("set tidb_plan_cache_invalidation_on_fresh_stats = 1")
tk.MustExec(`execute st using @a`) // stats changes can affect prep cache hit if we turn on the variable
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("0"))
tk.MustExec(`execute st using @a`)
tk.MustQuery(`select @@last_plan_from_cache`).Check(testkit.Rows("1"))
Expand Down
25 changes: 24 additions & 1 deletion session/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -865,11 +865,14 @@ const (
version142 = 142
// version 143 add column `error` to `mysql.tidb_global_task` and `mysql.tidb_background_subtask`
version143 = 143
// version 144 turn off `tidb_plan_cache_invalidation_on_fresh_stats`, which is introduced in 7.1-rc,
// if it's upgraded from an existing old version cluster.
version144 = 144
)

// currentBootstrapVersion is defined as a variable, so we can modify its value for testing.
// please make sure this is the largest version
var currentBootstrapVersion int64 = version143
var currentBootstrapVersion int64 = version144

// DDL owner key's expired time is ManagerSessionTTL seconds, we should wait the time and give more time to have a chance to finish it.
var internalSQLTimeout = owner.ManagerSessionTTL + 15
Expand Down Expand Up @@ -1001,6 +1004,7 @@ var (
upgradeToVer141,
upgradeToVer142,
upgradeToVer143,
upgradeToVer144,
}
)

Expand Down Expand Up @@ -2506,6 +2510,25 @@ func upgradeToVer143(s Session, ver int64) {
doReentrantDDL(s, "ALTER TABLE mysql.tidb_background_subtask ADD COLUMN `error` BLOB", infoschema.ErrColumnExists)
}

func upgradeToVer144(s Session, ver int64) {
if ver >= version144 {
return
}
ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnBootstrap)
rs, err := s.ExecuteInternal(ctx, "SELECT VARIABLE_VALUE FROM %n.%n WHERE VARIABLE_NAME=%?;",
mysql.SystemDB, mysql.GlobalVariablesTable, variable.TiDBPlanCacheInvalidationOnFreshStats)
terror.MustNil(err)
req := rs.NewChunk(nil)
err = rs.Next(ctx, req)
terror.MustNil(err)
if req.NumRows() != 0 {
return
}

mustExecute(s, "INSERT HIGH_PRIORITY IGNORE INTO %n.%n VALUES (%?, %?);",
mysql.SystemDB, mysql.GlobalVariablesTable, variable.TiDBPlanCacheInvalidationOnFreshStats, variable.Off)
}

func writeOOMAction(s Session) {
comment := "oom-action is `log` by default in v3.0.x, `cancel` by default in v4.0.11+"
mustExecute(s, `INSERT HIGH_PRIORITY INTO %n.%n VALUES (%?, %?, %?) ON DUPLICATE KEY UPDATE VARIABLE_VALUE= %?`,
Expand Down
47 changes: 47 additions & 0 deletions session/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2131,3 +2131,50 @@ func TestTiDBLoadBasedReplicaReadThresholdUpgradingToVer141(t *testing.T) {
require.Equal(t, 2, row.Len())
require.Equal(t, "1s", row.GetString(1))
}

func TestTiDBPlanCacheInvalidationOnFreshStatsWhenUpgradingToVer144(t *testing.T) {
ctx := context.Background()
store, _ := CreateStoreAndBootstrap(t)
defer func() { require.NoError(t, store.Close()) }()

// bootstrap as version143
ver143 := version143
seV143 := CreateSessionAndSetID(t, store)
txn, err := store.Begin()
require.NoError(t, err)
m := meta.NewMeta(txn)
err = m.FinishBootstrap(int64(ver143))
require.NoError(t, err)
mustExec(t, seV143, fmt.Sprintf("update mysql.tidb set variable_value=%d where variable_name='tidb_server_version'", ver143))
// simulate a real ver143 where `tidb_plan_cache_invalidation_on_fresh_stats` doesn't exist yet
mustExec(t, seV143, "delete from mysql.GLOBAL_VARIABLES where variable_name='tidb_plan_cache_invalidation_on_fresh_stats'")
err = txn.Commit(context.Background())
require.NoError(t, err)
unsetStoreBootstrapped(store.UUID())

// upgrade to ver144
domCurVer, err := BootstrapSession(store)
require.NoError(t, err)
defer domCurVer.Close()
seCurVer := CreateSessionAndSetID(t, store)
ver, err := getBootstrapVersion(seCurVer)
require.NoError(t, err)
require.Equal(t, currentBootstrapVersion, ver)

// the value in the table is set to OFF automatically
res := mustExecToRecodeSet(t, seCurVer, "select * from mysql.GLOBAL_VARIABLES where variable_name='tidb_plan_cache_invalidation_on_fresh_stats'")
chk := res.NewChunk(nil)
require.NoError(t, res.Next(ctx, chk))
require.Equal(t, 1, chk.NumRows())
row := chk.GetRow(0)
require.Equal(t, "OFF", row.GetString(1))

// the session and global variable is also OFF
res = mustExecToRecodeSet(t, seCurVer, "select @@session.tidb_plan_cache_invalidation_on_fresh_stats, @@global.tidb_plan_cache_invalidation_on_fresh_stats")
chk = res.NewChunk(nil)
require.NoError(t, res.Next(ctx, chk))
require.Equal(t, 1, chk.NumRows())
row = chk.GetRow(0)
require.Equal(t, int64(0), row.GetInt64(0))
require.Equal(t, int64(0), row.GetInt64(1))
}
4 changes: 4 additions & 0 deletions sessionctx/variable/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,10 @@ type SessionVars struct {
// EnableNonPreparedPlanCacheForDML indicates whether to enable non-prepared plan cache for DML statements.
EnableNonPreparedPlanCacheForDML bool

// PlanCacheInvalidationOnFreshStats controls if plan cache will be invalidated automatically when
// related stats are analyzed after the plan cache is generated.
PlanCacheInvalidationOnFreshStats bool

// NonPreparedPlanCacheSize controls the size of non-prepared plan cache.
NonPreparedPlanCacheSize uint64

Expand Down
4 changes: 4 additions & 0 deletions sessionctx/variable/sysvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -2505,6 +2505,10 @@ var defaultSysVars = []*SysVar{
s.OptimizerFixControl = newMap
return nil
}},
{Scope: ScopeGlobal | ScopeSession, Name: TiDBPlanCacheInvalidationOnFreshStats, Value: BoolToOnOff(DefTiDBPlanCacheInvalidationOnFreshStats), Type: TypeBool, SetSession: func(s *SessionVars, val string) error {
s.PlanCacheInvalidationOnFreshStats = TiDBOptOn(val)
return nil
}},
}

func setTiFlashComputeDispatchPolicy(s *SessionVars, val string) error {
Expand Down
4 changes: 4 additions & 0 deletions sessionctx/variable/tidb_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,9 @@ const (
TiDBNonPreparedPlanCacheSize = "tidb_non_prepared_plan_cache_size"
// TiDBPlanCacheMaxPlanSize controls the maximum size of a plan that can be cached.
TiDBPlanCacheMaxPlanSize = "tidb_plan_cache_max_plan_size"
// TiDBPlanCacheInvalidationOnFreshStats controls if plan cache will be invalidated automatically when
// related stats are analyzed after the plan cache is generated.
TiDBPlanCacheInvalidationOnFreshStats = "tidb_plan_cache_invalidation_on_fresh_stats"
// TiDBSessionPlanCacheSize controls the size of session plan cache.
TiDBSessionPlanCacheSize = "tidb_session_plan_cache_size"

Expand Down Expand Up @@ -1260,6 +1263,7 @@ const (
DefTiDBLoadBasedReplicaReadThreshold = time.Second
DefTiDBOptEnableLateMaterialization = true
DefTiDBOptOrderingIdxSelThresh = 0.0
DefTiDBPlanCacheInvalidationOnFreshStats = true
)

// Process global variables.
Expand Down

0 comments on commit 0b8f880

Please sign in to comment.