Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: fix the issue that binding cannot work when sql_select_limit is enabled #29789

Merged
merged 17 commits into from
Nov 23, 2021
1 change: 0 additions & 1 deletion executor/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (*ExecStm
if err != nil {
return nil, err
}
stmtNode = plannercore.TryAddExtraLimit(c.Ctx, stmtNode)

finalPlan, names, err := planner.Optimize(ctx, c.Ctx, stmtNode, ret.InfoSchema)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4707,6 +4707,26 @@ func (s *testIntegrationSuite) TestIssue27797(c *C) {
result.Check(testkit.Rows("<nil>"))
}

func (s *testIntegrationSuite) TestIssue27949(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t27949")
tk.MustExec("create table t27949 (a int, b int, key(b))")
tk.MustQuery("explain select * from t27949 where b=1").Check(testkit.Rows("IndexLookUp_10 10.00 root ",
qw4990 marked this conversation as resolved.
Show resolved Hide resolved
"├─IndexRangeScan_8(Build) 10.00 cop[tikv] table:t27949, index:b(b) range:[1,1], keep order:false, stats:pseudo",
"└─TableRowIDScan_9(Probe) 10.00 cop[tikv] table:t27949 keep order:false, stats:pseudo"))
tk.MustExec("create global binding for select * from t27949 where b=1 using select * from t27949 ignore index(b) where b=1")
tk.MustQuery("explain select * from t27949 where b=1").Check(testkit.Rows("TableReader_7 10.00 root data:Selection_6",
"└─Selection_6 10.00 cop[tikv] eq(test.t27949.b, 1)",
" └─TableFullScan_5 10000.00 cop[tikv] table:t27949 keep order:false, stats:pseudo"))
tk.MustExec("set @@sql_select_limit=100")
tk.MustQuery("explain select * from t27949 where b=1").Check(testkit.Rows("Limit_8 10.00 root offset:0, count:100",
"└─TableReader_13 10.00 root data:Limit_12",
" └─Limit_12 10.00 cop[tikv] offset:0, count:100",
" └─Selection_11 10.00 cop[tikv] eq(test.t27949.b, 1)",
" └─TableFullScan_10 10000.00 cop[tikv] table:t27949 keep order:false, stats:pseudo"))
}

func (s *testIntegrationSuite) TestIssue28154(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")
Expand Down
50 changes: 27 additions & 23 deletions planner/optimize.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,34 @@ func GetExecuteForUpdateReadIS(node ast.Node, sctx sessionctx.Context) infoschem
return nil
}

func matchSQLBinding(node ast.Node, sctx sessionctx.Context) (bindRecord *bindinfo.BindRecord, scope string, matched bool) {
useBinding := sctx.GetSessionVars().UsePlanBaselines
stmtNode, ok := node.(ast.StmtNode)
if !ok {
useBinding = false
}
if !useBinding {
return nil, "", false
}
var err error
bindRecord, scope, err = getBindRecord(sctx, stmtNode)
if err != nil || bindRecord == nil || len(bindRecord.Bindings) == 0 {
return nil, "", false
}
return bindRecord, scope, true
}

// Optimize does optimization and creates a Plan.
// The node must be prepared first.
func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (plannercore.Plan, types.NameSlice, error) {
sessVars := sctx.GetSessionVars()

bindRecord, scope, useBinding := matchSQLBinding(node, sctx)
qw4990 marked this conversation as resolved.
Show resolved Hide resolved
qw4990 marked this conversation as resolved.
Show resolved Hide resolved
qw4990 marked this conversation as resolved.
Show resolved Hide resolved
// add the extra Limit after matching the bind record
if stmtNode, ok := node.(ast.StmtNode); ok {
node = plannercore.TryAddExtraLimit(sctx, stmtNode)
}

// Because for write stmt, TiFlash has a different results when lock the data in point get plan. We ban the TiFlash
// engine in not read only stmt.
if _, isolationReadContainTiFlash := sessVars.IsolationReadEngines[kv.TiFlash]; isolationReadContainTiFlash && !IsReadOnly(node, sessVars) {
Expand Down Expand Up @@ -144,30 +167,11 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
}
sctx.PrepareTSFuture(ctx)

useBinding := sessVars.UsePlanBaselines
stmtNode, ok := node.(ast.StmtNode)
if !ok {
useBinding = false
}
var (
bindRecord *bindinfo.BindRecord
scope string
err error
)
if useBinding {
bindRecord, scope, err = getBindRecord(sctx, stmtNode)
if err != nil || bindRecord == nil || len(bindRecord.Bindings) == 0 {
useBinding = false
}
}
if useBinding && sessVars.SelectLimit != math.MaxUint64 {
sessVars.StmtCtx.AppendWarning(errors.New("sql_select_limit is set, ignore SQL bindings"))
useBinding = false
}

var names types.NameSlice
var bestPlan, bestPlanFromBind plannercore.Plan
var err error
if useBinding {
stmtNode := node.(ast.StmtNode) // must be StmtNode if useBinding is true
minCost := math.MaxFloat64
var (
bindStmtHints stmtctx.StmtHints
Expand Down Expand Up @@ -236,7 +240,7 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
}()
if sessVars.EvolvePlanBaselines && bestPlanFromBind != nil {
// Check bestPlanFromBind firstly to avoid nil stmtNode.
if _, ok := stmtNode.(*ast.SelectStmt); ok && !bindRecord.Bindings[0].Hint.ContainTableHint(plannercore.HintReadFromStorage) {
if _, ok := node.(*ast.SelectStmt); ok && !bindRecord.Bindings[0].Hint.ContainTableHint(plannercore.HintReadFromStorage) {
sessVars.StmtCtx.StmtHints = originStmtHints
defPlan, _, _, err := optimize(ctx, sctx, node, is)
if err != nil {
Expand All @@ -256,7 +260,7 @@ func Optimize(ctx context.Context, sctx sessionctx.Context, node ast.Node, is in
defPlanHintsStr := hint.RestoreOptimizerHints(defPlanHints)
binding := bindRecord.FindBinding(defPlanHintsStr)
if binding == nil {
handleEvolveTasks(ctx, sctx, bindRecord, stmtNode, defPlanHintsStr)
handleEvolveTasks(ctx, sctx, bindRecord, node.(ast.StmtNode), defPlanHintsStr)
}
}
}
Expand Down