diff --git a/br/tests/br_tikv_outage/run.sh b/br/tests/br_tikv_outage/run.sh index d419e3d0ee95b..2f1247c06ad36 100644 --- a/br/tests/br_tikv_outage/run.sh +++ b/br/tests/br_tikv_outage/run.sh @@ -18,7 +18,7 @@ for failure in $cases; do rm -f "$hint_finegrained" "$hint_backup_start" "$hint_get_backup_client" export GO_FAILPOINTS="github.com/pingcap/tidb/br/pkg/backup/hint-backup-start=1*return(\"$hint_backup_start\");\ github.com/pingcap/tidb/br/pkg/backup/hint-fine-grained-backup=1*return(\"$hint_finegrained\");\ -github.com/pingcap/tidb/br/pkg/conn/hint-get-backup-client=1*return(\"$hint_get_backup_client\")" +github.com/pingcap/tidb/br/pkg/utils/hint-get-backup-client=1*return(\"$hint_get_backup_client\")" backup_dir=${TEST_DIR:?}/"backup{test:${TEST_NAME}|with:${failure}}" rm -rf "${backup_dir:?}" diff --git a/br/tests/br_tikv_outage2/run.sh b/br/tests/br_tikv_outage2/run.sh index a482af29a08a0..aa963dfd52914 100644 --- a/br/tests/br_tikv_outage2/run.sh +++ b/br/tests/br_tikv_outage2/run.sh @@ -18,7 +18,7 @@ for failure in $cases; do rm -f "$hint_finegrained" "$hint_backup_start" "$hint_get_backup_client" export GO_FAILPOINTS="github.com/pingcap/tidb/br/pkg/backup/hint-backup-start=1*return(\"$hint_backup_start\");\ github.com/pingcap/tidb/br/pkg/backup/hint-fine-grained-backup=1*return(\"$hint_finegrained\");\ -github.com/pingcap/tidb/br/pkg/conn/hint-get-backup-client=1*return(\"$hint_get_backup_client\")" +github.com/pingcap/tidb/br/pkg/utils/hint-get-backup-client=1*return(\"$hint_get_backup_client\")" if [ "$failure" = outage-at-finegrained ]; then export GO_FAILPOINTS="$GO_FAILPOINTS;github.com/pingcap/tidb/br/pkg/backup/noop-backup=return(true)" fi diff --git a/planner/core/physical_plans.go b/planner/core/physical_plans.go index 3e04dea447572..e1b43e6bf0975 100644 --- a/planner/core/physical_plans.go +++ b/planner/core/physical_plans.go @@ -1295,6 +1295,11 @@ type PhysicalSelection struct { basePhysicalPlan Conditions []expression.Expression + + // The flag indicates whether this Selection is from a DataSource. + // The flag is only used by cost model for compatibility and will be removed later. + // Please see https://github.com/pingcap/tidb/issues/36243 for more details. + fromDataSource bool } // Clone implements PhysicalPlan interface. diff --git a/planner/core/plan_cost.go b/planner/core/plan_cost.go index 73758b562536a..6dc4132fa2ba2 100644 --- a/planner/core/plan_cost.go +++ b/planner/core/plan_cost.go @@ -81,6 +81,9 @@ func (p *PhysicalSelection) GetPlanCost(taskType property.TaskType, costFlag uin return 0, errors.Errorf("unknown task type %v", taskType) } selfCost = getCardinality(p.children[0], costFlag) * cpuFactor + if p.fromDataSource { + selfCost = 0 // for compatibility, see https://github.com/pingcap/tidb/issues/36243 + } case modelVer2: // selection cost: rows * num-filters * cpu-factor var cpuFactor float64 switch taskType { diff --git a/planner/core/plan_cost_test.go b/planner/core/plan_cost_test.go index d8bf5833412ce..3bc86b0231971 100644 --- a/planner/core/plan_cost_test.go +++ b/planner/core/plan_cost_test.go @@ -16,6 +16,7 @@ package core_test import ( "fmt" + "strconv" "strings" "testing" @@ -967,3 +968,39 @@ func TestTrueCardCost(t *testing.T) { checkPlanCost(`select * from t where a>10 limit 10`) checkPlanCost(`select sum(a), b*2 from t use index(b) group by b order by sum(a) limit 10`) } + +func TestIssue36243(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + tk := testkit.NewTestKit(t, store) + + tk.MustExec("use test") + tk.MustExec(`create table t (a int)`) + tk.MustExec(`insert into mysql.expr_pushdown_blacklist values ('>','tikv','')`) + tk.MustExec(`admin reload expr_pushdown_blacklist`) + tk.MustExec(`set @@tidb_enable_new_cost_interface=1`) + + getCost := func() (selCost, readerCost float64) { + res := tk.MustQuery(`explain format=verbose select * from t where a>0`).Rows() + // TableScan -> TableReader -> Selection + require.Equal(t, len(res), 3) + require.Contains(t, res[0][0], "Selection") + require.Contains(t, res[1][0], "TableReader") + require.Contains(t, res[2][0], "Scan") + var err error + selCost, err = strconv.ParseFloat(res[0][2].(string), 64) + require.NoError(t, err) + readerCost, err = strconv.ParseFloat(res[1][2].(string), 64) + require.NoError(t, err) + return + } + + tk.MustExec(`set @@tidb_cost_model_version=1`) + // Selection has the same cost with TableReader, ignore Selection cost for compatibility in cost model ver1. + selCost, readerCost := getCost() + require.Equal(t, selCost, readerCost) + + tk.MustExec(`set @@tidb_cost_model_version=2`) + selCost, readerCost = getCost() + require.True(t, selCost > readerCost) +} diff --git a/planner/core/task.go b/planner/core/task.go index 7d88aac896812..8181f985cc61f 100644 --- a/planner/core/task.go +++ b/planner/core/task.go @@ -809,6 +809,7 @@ func (t *copTask) handleRootTaskConds(ctx sessionctx.Context, newTask *rootTask) selectivity = SelectionFactor } sel := PhysicalSelection{Conditions: t.rootTaskConds}.Init(ctx, newTask.p.statsInfo().Scale(selectivity), newTask.p.SelectBlockOffset()) + sel.fromDataSource = true sel.SetChildren(newTask.p) newTask.p = sel sel.cost = newTask.cost()