Skip to content

Commit

Permalink
planner: support create binding from history (#39436)
Browse files Browse the repository at this point in the history
ref #39199
  • Loading branch information
fzzf678 authored Dec 1, 2022
1 parent e307642 commit 202f723
Show file tree
Hide file tree
Showing 13 changed files with 3,920 additions and 3,740 deletions.
2 changes: 1 addition & 1 deletion bindinfo/bind_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (c *bindCache) GetBindRecordBySQLDigest(sqlDigest string) (*BindRecord, err
return nil, errors.New("more than 1 binding matched")
}
if len(bindings) == 0 || len(bindings[0].Bindings) == 0 {
return nil, errors.New("can't find any binding for `" + sqlDigest + "`")
return nil, errors.New("can't find any binding for '" + sqlDigest + "'")
}
return bindings[0], nil
}
Expand Down
53 changes: 52 additions & 1 deletion bindinfo/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,57 @@ func TestDropBindBySQLDigest(t *testing.T) {
}

// exception cases
tk.MustGetErrMsg(fmt.Sprintf("drop binding for sql digest '%s'", "1"), "can't find any binding for `1`")
tk.MustGetErrMsg(fmt.Sprintf("drop binding for sql digest '%s'", "1"), "can't find any binding for '1'")
tk.MustGetErrMsg(fmt.Sprintf("drop binding for sql digest '%s'", ""), "sql digest is empty")
}

func TestCreateBindingFromHistory(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
require.NoError(t, tk.Session().Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil))

tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t1(id int primary key, a int, b int, key(a))")
tk.MustExec("create table t2(id int primary key, a int, b int, key(a))")

var testCases = []struct {
sqls []string
hint string
}{
{
sqls: []string{
"select %s * from t1, t2 where t1.id = t2.id",
"select %s * from test.t1, t2 where t1.id = t2.id",
"select %s * from test.t1, test.t2 where t1.id = t2.id",
"select %s * from t1, test.t2 where t1.id = t2.id",
},
hint: "/*+ merge_join(t1, t2) */",
},
{
sqls: []string{
"select %s * from t1 where a = 1",
"select %s * from test.t1 where a = 1",
},
hint: "/*+ ignore_index(t, a) */",
},
}

for _, testCase := range testCases {
for _, bind := range testCase.sqls {
stmtsummary.StmtSummaryByDigestMap.Clear()
bindSQL := fmt.Sprintf(bind, testCase.hint)
tk.MustExec(bindSQL)
planDigest := tk.MustQuery(fmt.Sprintf("select plan_digest from information_schema.statements_summary where query_sample_text = '%s'", bindSQL)).Rows()
tk.MustExec(fmt.Sprintf("create session binding from history using plan digest '%s'", planDigest[0][0]))
for _, sql := range testCase.sqls {
tk.MustExec(fmt.Sprintf(sql, ""))
tk.MustQuery("select @@last_plan_from_binding").Check(testkit.Rows("1"))
}
}
}

// exception cases
tk.MustGetErrMsg(fmt.Sprintf("create binding from history using plan digest '%s'", "1"), "can't find any plans for '1'")
tk.MustGetErrMsg(fmt.Sprintf("create binding from history using plan digest '%s'", ""), "plan digest is empty")
}
3 changes: 2 additions & 1 deletion executor/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type SQLBindExec struct {
isGlobal bool
bindAst ast.StmtNode
newStatus string
source string // by manual or from history, only in create stmt
sqlDigest string
planDigest string
}
Expand Down Expand Up @@ -131,7 +132,7 @@ func (e *SQLBindExec) createSQLBind() error {
Charset: e.charset,
Collation: e.collation,
Status: bindinfo.Enabled,
Source: bindinfo.Manual,
Source: e.source,
SQLDigest: e.sqlDigest,
}
record := &bindinfo.BindRecord{
Expand Down
1 change: 1 addition & 0 deletions executor/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4815,6 +4815,7 @@ func (b *executorBuilder) buildSQLBindExec(v *plannercore.SQLBindPlan) Executor
isGlobal: v.IsGlobal,
bindAst: v.BindStmt,
newStatus: v.NewStatus,
source: v.Source,
sqlDigest: v.SQLDigest,
}
return e
Expand Down
40 changes: 24 additions & 16 deletions parser/ast/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1826,6 +1826,7 @@ type CreateBindingStmt struct {
GlobalScope bool
OriginNode StmtNode
HintedNode StmtNode
PlanDigest string
}

func (n *CreateBindingStmt) Restore(ctx *format.RestoreCtx) error {
Expand All @@ -1835,13 +1836,18 @@ func (n *CreateBindingStmt) Restore(ctx *format.RestoreCtx) error {
} else {
ctx.WriteKeyWord("SESSION ")
}
ctx.WriteKeyWord("BINDING FOR ")
if err := n.OriginNode.Restore(ctx); err != nil {
return errors.Trace(err)
}
ctx.WriteKeyWord(" USING ")
if err := n.HintedNode.Restore(ctx); err != nil {
return errors.Trace(err)
if n.OriginNode == nil {
ctx.WriteKeyWord("BINDING FROM HISTORY USING PLAN DIGEST ")
ctx.WriteString(n.PlanDigest)
} else {
ctx.WriteKeyWord("BINDING FOR ")
if err := n.OriginNode.Restore(ctx); err != nil {
return errors.Trace(err)
}
ctx.WriteKeyWord(" USING ")
if err := n.HintedNode.Restore(ctx); err != nil {
return errors.Trace(err)
}
}
return nil
}
Expand All @@ -1852,16 +1858,18 @@ func (n *CreateBindingStmt) Accept(v Visitor) (Node, bool) {
return v.Leave(newNode)
}
n = newNode.(*CreateBindingStmt)
origNode, ok := n.OriginNode.Accept(v)
if !ok {
return n, false
}
n.OriginNode = origNode.(StmtNode)
hintedNode, ok := n.HintedNode.Accept(v)
if !ok {
return n, false
if n.OriginNode != nil {
origNode, ok := n.OriginNode.Accept(v)
if !ok {
return n, false
}
n.OriginNode = origNode.(StmtNode)
hintedNode, ok := n.HintedNode.Accept(v)
if !ok {
return n, false
}
n.HintedNode = hintedNode.(StmtNode)
}
n.HintedNode = hintedNode.(StmtNode)
return v.Leave(n)
}

Expand Down
Loading

0 comments on commit 202f723

Please sign in to comment.