diff --git a/pkg/planner/core/plan_cache_lru.go b/pkg/planner/core/plan_cache_lru.go index 6be81eac0246e..87ef3edc674d5 100644 --- a/pkg/planner/core/plan_cache_lru.go +++ b/pkg/planner/core/plan_cache_lru.go @@ -253,61 +253,13 @@ func (l *LRUPlanCache) memoryControl() { // PickPlanFromBucket pick one plan from bucket func (l *LRUPlanCache) pickFromBucket(bucket map[*list.Element]struct{}, matchOpts *utilpc.PlanCacheMatchOpts) (*list.Element, bool) { for k := range bucket { - if matchOpts == nil { // for PointGet Plan + if matchCachedPlan(l.sctx, k.Value.(*planCacheEntry).PlanValue.(*PlanCacheValue), matchOpts) { return k, true } - - plan := k.Value.(*planCacheEntry).PlanValue.(*PlanCacheValue) - // check param types' compatibility - ok1 := checkTypesCompatibility4PC(plan.matchOpts.ParamTypes, matchOpts.ParamTypes) - if !ok1 { - continue - } - - // check limit offset and key if equal and check switch if enabled - ok2 := checkUint64SliceIfEqual(plan.matchOpts.LimitOffsetAndCount, matchOpts.LimitOffsetAndCount) - if !ok2 { - continue - } - if len(plan.matchOpts.LimitOffsetAndCount) > 0 && !l.sctx.GetSessionVars().EnablePlanCacheForParamLimit { - // offset and key slice matched, but it is a plan with param limit and the switch is disabled - continue - } - // check subquery switch state - if plan.matchOpts.HasSubQuery && !l.sctx.GetSessionVars().EnablePlanCacheForSubquery { - continue - } - // table stats has changed - // 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 - } - - // below are some SQL variables that can affect the plan - if plan.matchOpts.ForeignKeyChecks != matchOpts.ForeignKeyChecks { - continue - } - return k, true } return nil, false } -func checkUint64SliceIfEqual(a, b []uint64) bool { - if (a == nil && b != nil) || (a != nil && b == nil) { - return false - } - if len(a) != len(b) { - return false - } - for i := range a { - if a[i] != b[i] { - return false - } - } - return true -} - // updateInstanceMetric update the memory usage and plan num for show in grafana func (l *LRUPlanCache) updateInstanceMetric(in, out *planCacheEntry) { updateInstancePlanNum(in, out) diff --git a/pkg/planner/core/plan_cache_utils.go b/pkg/planner/core/plan_cache_utils.go index 3565cbf3767f3..39d41242b6bc6 100644 --- a/pkg/planner/core/plan_cache_utils.go +++ b/pkg/planner/core/plan_cache_utils.go @@ -750,3 +750,37 @@ func parseParamTypes(sctx sessionctx.Context, params []expression.Expression) (p } return } + +// matchCachedPlan checks whether this plan is matched with these match-options. +func matchCachedPlan(sctx sessionctx.Context, value *PlanCacheValue, matchOpts *utilpc.PlanCacheMatchOpts) bool { + if matchOpts == nil { // if PointGet, the matchOpts is nil + return true + } + if !checkTypesCompatibility4PC(value.matchOpts.ParamTypes, matchOpts.ParamTypes) { + return false + } + // check limit offset and key if equal and check switch if enabled + if !slices.Equal(value.matchOpts.LimitOffsetAndCount, matchOpts.LimitOffsetAndCount) { + return false + } + if len(value.matchOpts.LimitOffsetAndCount) > 0 && !sctx.GetSessionVars().EnablePlanCacheForParamLimit { + // offset and key slice matched, but it is a plan with param limit and the switch is disabled + return false + } + // check subquery switch state + if value.matchOpts.HasSubQuery && !sctx.GetSessionVars().EnablePlanCacheForSubquery { + return false + } + + // table stats has changed + // this check can be disabled by turning off system variable tidb_plan_cache_invalidation_on_fresh_stats + if sctx.GetSessionVars().PlanCacheInvalidationOnFreshStats && + value.matchOpts.StatsVersionHash != matchOpts.StatsVersionHash { + return false + } + // below are some SQL variables that can affect the plan + if value.matchOpts.ForeignKeyChecks != matchOpts.ForeignKeyChecks { + return false + } + return true +}