Skip to content

Commit

Permalink
*: remove non-prepared plan cache (#7040)
Browse files Browse the repository at this point in the history
* *: remove non-prepared plan cache

non-prepared plan cache is not usable if we can only do full string match.
And further development doesn't worth the effort.
  • Loading branch information
coocood authored and ngaut committed Jul 13, 2018
1 parent 34d8fd8 commit 63c4562
Show file tree
Hide file tree
Showing 10 changed files with 29 additions and 263 deletions.
6 changes: 0 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ type Config struct {
Status Status `toml:"status" json:"status"`
Performance Performance `toml:"performance" json:"performance"`
XProtocol XProtocol `toml:"xprotocol" json:"xprotocol"`
PlanCache PlanCache `toml:"plan-cache" json:"plan-cache"`
PreparedPlanCache PreparedPlanCache `toml:"prepared-plan-cache" json:"prepared-plan-cache"`
OpenTracing OpenTracing `toml:"opentracing" json:"opentracing"`
ProxyProtocol ProxyProtocol `toml:"proxy-protocol" json:"proxy-protocol"`
Expand Down Expand Up @@ -287,11 +286,6 @@ var defaultConf = Config{
Networks: "",
HeaderTimeout: 5,
},
PlanCache: PlanCache{
Enabled: false,
Capacity: 2560,
Shards: 256,
},
PreparedPlanCache: PreparedPlanCache{
Enabled: false,
Capacity: 100,
Expand Down
5 changes: 0 additions & 5 deletions config/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,6 @@ networks = ""
# PROXY protocol header read timeout, unit is second
header-timeout = 5

[plan-cache]
enabled = false
capacity = 2560
shards = 256

[prepared-plan-cache]
enabled = false
capacity = 100
Expand Down
17 changes: 0 additions & 17 deletions executor/aggregate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/terror"
"github.com/pingcap/tidb/util/kvcache"
"github.com/pingcap/tidb/util/testkit"
)

Expand Down Expand Up @@ -550,22 +549,6 @@ func (s *testSuite) TestAggEliminator(c *C) {
tk.MustQuery("select min(b*b) from t").Check(testkit.Rows("1"))
}

func (s *testSuite) TestIssue5663(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
plan.GlobalPlanCache = kvcache.NewShardedLRUCache(2, 1)
planCahche := tk.Se.GetSessionVars().PlanCacheEnabled
defer func() {
tk.Se.GetSessionVars().PlanCacheEnabled = planCahche
}()

tk.Se.GetSessionVars().PlanCacheEnabled = true
tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t1 (i int unsigned, primary key(i));")
tk.MustExec("insert into t1 values (1),(2),(3);")
tk.MustQuery("select group_concat(i) from t1 where i > 1;").Check(testkit.Rows("2,3"))
tk.MustQuery("select group_concat(i) from t1 where i > 1;").Check(testkit.Rows("2,3"))
}

func (s *testSuite) TestMaxMinFloatScalaFunc(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)

Expand Down
87 changes: 0 additions & 87 deletions plan/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package plan
import (
"time"

"github.com/pingcap/tidb/ast"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/util/codec"
Expand All @@ -25,82 +24,12 @@ import (
)

var (
// GlobalPlanCache stores the global plan cache for every session in a tidb-server.
GlobalPlanCache *kvcache.ShardedLRUCache

// PreparedPlanCacheEnabled stores the global config "prepared-plan-cache-enabled".
PreparedPlanCacheEnabled bool
// PreparedPlanCacheCapacity stores the global config "prepared-plan-cache-capacity".
PreparedPlanCacheCapacity uint
)

type sqlCacheKey struct {
user string
host string
database string
sql string
snapshot uint64
schemaVersion int64
sqlMode mysql.SQLMode
timezoneOffset int
readOnly bool // stores the current tidb-server status.

hash []byte
}

// Hash implements Key interface.
func (key *sqlCacheKey) Hash() []byte {
if key.hash == nil {
var (
userBytes = hack.Slice(key.user)
hostBytes = hack.Slice(key.host)
dbBytes = hack.Slice(key.database)
sqlBytes = hack.Slice(key.sql)
bufferSize = len(userBytes) + len(hostBytes) + len(dbBytes) + len(sqlBytes) + 8*4 + 1
)

key.hash = make([]byte, 0, bufferSize)
key.hash = append(key.hash, userBytes...)
key.hash = append(key.hash, hostBytes...)
key.hash = append(key.hash, dbBytes...)
key.hash = append(key.hash, sqlBytes...)
key.hash = codec.EncodeInt(key.hash, int64(key.snapshot))
key.hash = codec.EncodeInt(key.hash, key.schemaVersion)
key.hash = codec.EncodeInt(key.hash, int64(key.sqlMode))
key.hash = codec.EncodeInt(key.hash, int64(key.timezoneOffset))
if key.readOnly {
key.hash = append(key.hash, '1')
} else {
key.hash = append(key.hash, '0')
}
}
return key.hash
}

// NewSQLCacheKey creates a new sqlCacheKey object.
func NewSQLCacheKey(sessionVars *variable.SessionVars, sql string, schemaVersion int64, readOnly bool) kvcache.Key {
timezoneOffset, user, host := 0, "", ""
if sessionVars.TimeZone != nil {
_, timezoneOffset = time.Now().In(sessionVars.TimeZone).Zone()
}
if sessionVars.User != nil {
user = sessionVars.User.Username
host = sessionVars.User.Hostname
}

return &sqlCacheKey{
user: user,
host: host,
database: sessionVars.CurrentDB,
sql: sql,
snapshot: sessionVars.SnapshotTS,
schemaVersion: schemaVersion,
sqlMode: sessionVars.SQLMode,
timezoneOffset: timezoneOffset,
readOnly: readOnly,
}
}

type pstmtPlanCacheKey struct {
database string
connID uint64
Expand Down Expand Up @@ -149,22 +78,6 @@ func NewPSTMTPlanCacheKey(sessionVars *variable.SessionVars, pstmtID uint32, sch
}
}

// SQLCacheValue stores the cached Statement and StmtNode.
type SQLCacheValue struct {
StmtNode ast.StmtNode
Plan Plan
Expensive bool
}

// NewSQLCacheValue creates a SQLCacheValue.
func NewSQLCacheValue(ast ast.StmtNode, plan Plan, expensive bool) *SQLCacheValue {
return &SQLCacheValue{
StmtNode: ast,
Plan: plan,
Expensive: expensive,
}
}

// PSTMTPlanCacheValue stores the cached Statement and StmtNode.
type PSTMTPlanCacheValue struct {
Plan Plan
Expand Down
6 changes: 2 additions & 4 deletions plan/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ func (s *testCacheSuite) SetUpSuite(c *C) {

func (s *testCacheSuite) TestCacheKey(c *C) {
defer testleak.AfterTest(c)()
key1 := NewSQLCacheKey(s.ctx.GetSessionVars(), "select * from t", 0, false)
c.Assert(key1.Hash(), DeepEquals, []byte{0x74, 0x65, 0x73, 0x74, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x2a, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30})
key2 := NewPSTMTPlanCacheKey(s.ctx.GetSessionVars(), 1, 1)
c.Assert(key2.Hash(), DeepEquals, []byte{0x74, 0x65, 0x73, 0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})
key := NewPSTMTPlanCacheKey(s.ctx.GetSessionVars(), 1, 1)
c.Assert(key.Hash(), DeepEquals, []byte{0x74, 0x65, 0x73, 0x74, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})
}
95 changes: 27 additions & 68 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -767,86 +767,45 @@ func (s *session) execute(ctx context.Context, sql string) (recordSets []ast.Rec
}

s.PrepareTxnCtx(ctx)
var (
cacheKey kvcache.Key
cacheValue kvcache.Value
hitCache = false
connID = s.sessionVars.ConnectionID
planCacheEnabled = s.sessionVars.PlanCacheEnabled // Its value is read from the global configuration, and it will be only updated in tests.
)
connID := s.sessionVars.ConnectionID
err = s.loadCommonGlobalVariablesIfNeeded()
if err != nil {
return nil, errors.Trace(err)
}

if planCacheEnabled {
schemaVersion := domain.GetDomain(s).InfoSchema().SchemaMetaVersion()
readOnly := s.Txn() == nil || s.Txn().IsReadOnly()
charsetInfo, collation := s.sessionVars.GetCharsetInfo()

cacheKey = plan.NewSQLCacheKey(s.sessionVars, sql, schemaVersion, readOnly)
cacheValue, hitCache = plan.GlobalPlanCache.Get(cacheKey)
// Step1: Compile query string to abstract syntax trees(ASTs).
startTS := time.Now()
stmtNodes, err := s.ParseSQL(ctx, sql, charsetInfo, collation)
if err != nil {
s.rollbackOnError(ctx)
log.Warnf("con:%d parse error:\n%v\n%s", connID, err, sql)
return nil, errors.Trace(err)
}
metrics.SessionExecuteParseDuration.Observe(time.Since(startTS).Seconds())

if hitCache {
metrics.PlanCacheCounter.WithLabelValues("select").Inc()
stmtNode := cacheValue.(*plan.SQLCacheValue).StmtNode
stmt := &executor.ExecStmt{
InfoSchema: executor.GetInfoSchema(s),
Plan: cacheValue.(*plan.SQLCacheValue).Plan,
Expensive: cacheValue.(*plan.SQLCacheValue).Expensive,
Text: stmtNode.Text(),
StmtNode: stmtNode,
Ctx: s,
}

compiler := executor.Compiler{Ctx: s}
for _, stmtNode := range stmtNodes {
s.PrepareTxnCtx(ctx)
if err = executor.ResetStmtCtx(s, stmtNode); err != nil {
return nil, errors.Trace(err)
}
if recordSets, err = s.executeStatement(ctx, connID, stmtNode, stmt, recordSets); err != nil {
return nil, errors.Trace(err)
}
} else {
err = s.loadCommonGlobalVariablesIfNeeded()
if err != nil {

// Step2: Transform abstract syntax tree to a physical plan(stored in executor.ExecStmt).
startTS = time.Now()
// Some executions are done in compile stage, so we reset them before compile.
if err := executor.ResetStmtCtx(s, stmtNode); err != nil {
return nil, errors.Trace(err)
}

charsetInfo, collation := s.sessionVars.GetCharsetInfo()

// Step1: Compile query string to abstract syntax trees(ASTs).
startTS := time.Now()
stmtNodes, err := s.ParseSQL(ctx, sql, charsetInfo, collation)
stmt, err := compiler.Compile(ctx, stmtNode)
if err != nil {
s.rollbackOnError(ctx)
log.Warnf("con:%d parse error:\n%v\n%s", connID, err, sql)
log.Warnf("con:%d compile error:\n%v\n%s", connID, err, sql)
return nil, errors.Trace(err)
}
metrics.SessionExecuteParseDuration.Observe(time.Since(startTS).Seconds())

compiler := executor.Compiler{Ctx: s}
for _, stmtNode := range stmtNodes {
s.PrepareTxnCtx(ctx)
metrics.SessionExecuteCompileDuration.Observe(time.Since(startTS).Seconds())

// Step2: Transform abstract syntax tree to a physical plan(stored in executor.ExecStmt).
startTS = time.Now()
// Some executions are done in compile stage, so we reset them before compile.
if err := executor.ResetStmtCtx(s, stmtNode); err != nil {
return nil, errors.Trace(err)
}
stmt, err := compiler.Compile(ctx, stmtNode)
if err != nil {
s.rollbackOnError(ctx)
log.Warnf("con:%d compile error:\n%v\n%s", connID, err, sql)
return nil, errors.Trace(err)
}
metrics.SessionExecuteCompileDuration.Observe(time.Since(startTS).Seconds())

// Step3: Cache the physical plan if possible.
if planCacheEnabled && stmt.Cacheable && len(stmtNodes) == 1 && !s.GetSessionVars().StmtCtx.HistogramsNotLoad() {
plan.GlobalPlanCache.Put(cacheKey, plan.NewSQLCacheValue(stmtNode, stmt.Plan, stmt.Expensive))
}

// Step4: Execute the physical plan.
if recordSets, err = s.executeStatement(ctx, connID, stmtNode, stmt, recordSets); err != nil {
return nil, errors.Trace(err)
}
// Step3: Execute the physical plan.
if recordSets, err = s.executeStatement(ctx, connID, stmtNode, stmt, recordSets); err != nil {
return nil, errors.Trace(err)
}
}

Expand Down
9 changes: 0 additions & 9 deletions session/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/privilege/privileges"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/sessionctx"
Expand All @@ -38,7 +37,6 @@ import (
"github.com/pingcap/tidb/terror"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/auth"
"github.com/pingcap/tidb/util/kvcache"
"github.com/pingcap/tidb/util/sqlexec"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"
Expand Down Expand Up @@ -110,18 +108,11 @@ func (p *mockBinlogPump) PullBinlogs(ctx context.Context, in *binlog.PullBinlogR
}

func (s *testSessionSuite) TestForCoverage(c *C) {
plan.GlobalPlanCache = kvcache.NewShardedLRUCache(2, 1)

// Just for test coverage.
tk := testkit.NewTestKitWithInit(c, s.store)
planCache := tk.Se.GetSessionVars().PlanCacheEnabled
defer func() {
tk.Se.GetSessionVars().PlanCacheEnabled = planCache
}()
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (id int auto_increment, v int, index (id))")
tk.MustExec("insert t values ()")
tk.Se.GetSessionVars().PlanCacheEnabled = true
tk.MustExec("insert t values ()")
tk.MustExec("insert t values ()")

Expand Down
4 changes: 0 additions & 4 deletions sessionctx/variable/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,6 @@ type SessionVars struct {
// PlanID is the unique id of logical and physical plan.
PlanID int

// PlanCacheEnabled stores the global config "plan-cache-enabled", and it will be only updated in tests.
PlanCacheEnabled bool

// User is the user identity with which the session login.
User *auth.UserIdentity

Expand Down Expand Up @@ -341,7 +338,6 @@ func NewSessionVars() *SessionVars {
} else {
enableStreaming = "0"
}
vars.PlanCacheEnabled = config.GetGlobalConfig().PlanCache.Enabled
terror.Log(vars.SetSystemVar(TiDBEnableStreaming, enableStreaming))
return vars
}
Expand Down
5 changes: 0 additions & 5 deletions tidb-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import (
"github.com/pingcap/tidb/store/tikv/gcworker"
"github.com/pingcap/tidb/terror"
"github.com/pingcap/tidb/util"
"github.com/pingcap/tidb/util/kvcache"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/printer"
"github.com/pingcap/tidb/util/systimemon"
Expand Down Expand Up @@ -380,10 +379,6 @@ func setGlobalVars() {
plan.AllowCartesianProduct = cfg.Performance.CrossJoin
privileges.SkipWithGrant = cfg.Security.SkipGrantTable

if cfg.PlanCache.Enabled {
plan.GlobalPlanCache = kvcache.NewShardedLRUCache(cfg.PlanCache.Capacity, cfg.PlanCache.Shards)
}

plan.PreparedPlanCacheEnabled = cfg.PreparedPlanCache.Enabled
if plan.PreparedPlanCacheEnabled {
plan.PreparedPlanCacheCapacity = cfg.PreparedPlanCache.Capacity
Expand Down
Loading

0 comments on commit 63c4562

Please sign in to comment.