Skip to content

Commit

Permalink
planner: add projection pushdown (#27029)
Browse files Browse the repository at this point in the history
close #26242
  • Loading branch information
ichn-hu authored Apr 22, 2022
1 parent 886dc81 commit 99b871e
Show file tree
Hide file tree
Showing 12 changed files with 528 additions and 7 deletions.
7 changes: 5 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,10 @@ type Performance struct {
CrossJoin bool `toml:"cross-join" json:"cross-join"`
RunAutoAnalyze bool `toml:"run-auto-analyze" json:"run-auto-analyze"`
DistinctAggPushDown bool `toml:"distinct-agg-push-down" json:"distinct-agg-push-down"`
CommitterConcurrency int `toml:"committer-concurrency" json:"committer-concurrency"`
MaxTxnTTL uint64 `toml:"max-txn-ttl" json:"max-txn-ttl"`
// Whether enable projection push down for coprocessors (both tikv & tiflash), default false.
ProjectionPushDown bool `toml:"projection-push-down" json:"projection-push-down"`
CommitterConcurrency int `toml:"committer-concurrency" json:"committer-concurrency"`
MaxTxnTTL uint64 `toml:"max-txn-ttl" json:"max-txn-ttl"`
// Deprecated
MemProfileInterval string `toml:"-" json:"-"`
IndexUsageSyncLease string `toml:"index-usage-sync-lease" json:"index-usage-sync-lease"`
Expand Down Expand Up @@ -693,6 +695,7 @@ var defaultConf = Config{
TxnEntrySizeLimit: DefTxnEntrySizeLimit,
TxnTotalSizeLimit: DefTxnTotalSizeLimit,
DistinctAggPushDown: false,
ProjectionPushDown: false,
CommitterConcurrency: defTiKVCfg.CommitterConcurrency,
MaxTxnTTL: defTiKVCfg.MaxTxnTTL, // 1hour
// TODO: set indexUsageSyncLease to 60s.
Expand Down
7 changes: 7 additions & 0 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -2050,6 +2050,13 @@ func (p *LogicalProjection) exhaustPhysicalPlans(prop *property.PhysicalProperty
mppProp.TaskTp = property.MppTaskType
newProps = append(newProps, mppProp)
}
if newProp.TaskTp != property.CopSingleReadTaskType && p.SCtx().GetSessionVars().AllowProjectionPushDown && p.canPushToCop(kv.TiKV) &&
expression.CanExprsPushDown(p.SCtx().GetSessionVars().StmtCtx, p.Exprs, p.SCtx().GetClient(), kv.TiKV) && !expression.ContainVirtualColumn(p.Exprs) {
copProp := newProp.CloneEssentialFields()
copProp.TaskTp = property.CopSingleReadTaskType
newProps = append(newProps, copProp)
}

ret := make([]PhysicalPlan, 0, len(newProps))
for _, newProp := range newProps {
proj := PhysicalProjection{
Expand Down
68 changes: 68 additions & 0 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,74 @@ func TestIssue32428(t *testing.T) {
tk.MustQuery(`execute stmt using @a`).Check(testkit.Rows()) // empty result
}

func TestPushDownProjectionForTiKV(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (a int, b real, i int, id int, value decimal(6,3), name char(128), d decimal(6,3), s char(128), t datetime, c bigint as ((a+1)) virtual, e real as ((b+a)))")
tk.MustExec("analyze table t")
tk.MustExec("set session tidb_opt_projection_push_down=1")

var input []string
var output []struct {
SQL string
Plan []string
}
integrationSuiteData := core.GetIntegrationSuiteData()
integrationSuiteData.GetTestCases(t, &input, &output)
for i, tt := range input {
testdata.OnRecord(func() {
output[i].SQL = tt
output[i].Plan = testdata.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
})
res := tk.MustQuery(tt)
res.Check(testkit.Rows(output[i].Plan...))
}
}

func TestPushDownProjectionForTiFlashCoprocessor(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("create table t (a int, b real, i int, id int, value decimal(6,3), name char(128), d decimal(6,3), s char(128), t datetime, c bigint as ((a+1)) virtual, e real as ((b+a)))")
tk.MustExec("analyze table t")
tk.MustExec("set session tidb_opt_projection_push_down=1")

// Create virtual tiflash replica info.
dom := domain.GetDomain(tk.Session())
is := dom.InfoSchema()
db, exists := is.SchemaByName(model.NewCIStr("test"))
require.True(t, exists)
for _, tblInfo := range db.Tables {
if tblInfo.Name.L == "t" {
tblInfo.TiFlashReplica = &model.TiFlashReplicaInfo{
Count: 1,
Available: true,
}
}
}

var input []string
var output []struct {
SQL string
Plan []string
}
integrationSuiteData := core.GetIntegrationSuiteData()
integrationSuiteData.GetTestCases(t, &input, &output)
for i, tt := range input {
testdata.OnRecord(func() {
output[i].SQL = tt
output[i].Plan = testdata.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
})
res := tk.MustQuery(tt)
res.Check(testkit.Rows(output[i].Plan...))
}
}

func TestPushDownProjectionForTiFlash(t *testing.T) {
store, clean := testkit.CreateMockStore(t)
defer clean()
Expand Down
2 changes: 1 addition & 1 deletion planner/core/physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (p *PhysicalIndexReader) SetSchema(_ *expression.Schema) {
if p.indexPlan != nil {
p.IndexPlans = flattenPushDownPlan(p.indexPlan)
switch p.indexPlan.(type) {
case *PhysicalHashAgg, *PhysicalStreamAgg:
case *PhysicalHashAgg, *PhysicalStreamAgg, *PhysicalProjection:
p.schema = p.indexPlan.Schema()
default:
is := p.IndexPlans[0].(*PhysicalIndexScan)
Expand Down
4 changes: 2 additions & 2 deletions planner/core/plan_to_pb.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ func (p *PhysicalProjection) ToPB(ctx sessionctx.Context, storeType kv.StoreType
Exprs: exprs,
}
executorID := ""
if storeType == kv.TiFlash {
if storeType == kv.TiFlash || storeType == kv.TiKV {
var err error
projExec.Child, err = p.children[0].ToPB(ctx, storeType)
if err != nil {
return nil, errors.Trace(err)
}
executorID = p.ExplainID().String()
} else {
return nil, errors.Errorf("The projection can only be pushed down to TiFlash now, not %s", storeType.Name())
return nil, errors.Errorf("the projection can only be pushed down to TiFlash or TiKV now, not %s", storeType.Name())
}
return &tipb.Executor{Tp: tipb.ExecType_TypeProjection, Projection: projExec, ExecutorId: &executorID}, nil
}
Expand Down
3 changes: 1 addition & 2 deletions planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -1460,7 +1460,7 @@ func (p *PhysicalProjection) GetCost(count float64) float64 {
func (p *PhysicalProjection) attach2Task(tasks ...task) task {
t := tasks[0].copy()
if cop, ok := t.(*copTask); ok {
if len(cop.rootTaskConds) == 0 && cop.getStoreType() == kv.TiFlash && expression.CanExprsPushDown(p.ctx.GetSessionVars().StmtCtx, p.Exprs, p.ctx.GetClient(), cop.getStoreType()) {
if len(cop.rootTaskConds) == 0 && expression.CanExprsPushDown(p.ctx.GetSessionVars().StmtCtx, p.Exprs, p.ctx.GetClient(), cop.getStoreType()) {
copTask := attachPlan2Task(p, cop)
copTask.addCost(p.GetCost(t.count()))
p.cost = copTask.cost()
Expand All @@ -1475,7 +1475,6 @@ func (p *PhysicalProjection) attach2Task(tasks ...task) task {
return mpp
}
}
// TODO: support projection push down for TiKV.
t = t.convertToRootTask(p.ctx)
t = attachPlan2Task(p, t)
t.addCost(p.GetCost(t.count()))
Expand Down
46 changes: 46 additions & 0 deletions planner/core/testdata/integration_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,52 @@
"explain format = 'brief' select /*+ inl_hash_join(s) */ * from t join s on t.a=s.a and t.a = s.b"
]
},
{
"name": "TestPushDownProjectionForTiKV",
"cases": [
"desc format = 'brief' select i * 2 from t",
"desc format = 'brief' select DATE_FORMAT(t, '%Y-%m-%d %H') as date from t",
"desc format = 'brief' select md5(s) from t",
"desc format = 'brief' select c from t where a+1=3",
"desc format = 'brief' select /*+ hash_agg()*/ count(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ hash_agg()*/ count(*) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ hash_agg()*/ sum(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ count(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ count(*) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ sum(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select * from (select id-2 as b from t) B join (select id-2 as b from t) A on A.b=B.b",
"desc format = 'brief' select * from t join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select * from t left join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select * from t right join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select A.b, B.b from (select id-2 as b from t) B join (select id-2 as b from t) A on A.b=B.b",
"desc format = 'brief' select A.id from t as A where exists (select 1 from t where t.id=A.id)",
"desc format = 'brief' select A.id from t as A where not exists (select 1 from t where t.id=A.id)",
"desc format = 'brief' SELECT FROM_UNIXTIME(name,'%Y-%m-%d') FROM t;"
]
},
{
"name": "TestPushDownProjectionForTiFlashCoprocessor",
"cases": [
"desc format = 'brief' select i * 2 from t",
"desc format = 'brief' select DATE_FORMAT(t, '%Y-%m-%d %H') as date from t",
"desc format = 'brief' select md5(s) from t",
"desc format = 'brief' select c from t where a+1=3",
"desc format = 'brief' select /*+ hash_agg()*/ count(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ hash_agg()*/ count(*) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ hash_agg()*/ sum(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ count(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ count(*) from (select id + 1 as b from t)A",
"desc format = 'brief' select /*+ stream_agg()*/ sum(b) from (select id + 1 as b from t)A",
"desc format = 'brief' select * from (select id-2 as b from t) B join (select id-2 as b from t) A on A.b=B.b",
"desc format = 'brief' select * from t join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select * from t left join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select * from t right join (select id-2 as b from t) A on A.b=t.id",
"desc format = 'brief' select A.b, B.b from (select id-2 as b from t) B join (select id-2 as b from t) A on A.b=B.b",
"desc format = 'brief' select A.id from t as A where exists (select 1 from t where t.id=A.id)",
"desc format = 'brief' select A.id from t as A where not exists (select 1 from t where t.id=A.id)",
"desc format = 'brief' SELECT FROM_UNIXTIME(name,'%Y-%m-%d') FROM t;"
]
},
{
"name": "TestPushDownProjectionForTiFlash",
"cases": [
Expand Down
Loading

0 comments on commit 99b871e

Please sign in to comment.