Skip to content

Commit

Permalink
planner: correct block offset for table as names (pingcap#12996)
Browse files Browse the repository at this point in the history
  • Loading branch information
alivxxx authored and XiaTianliang committed Dec 21, 2019
1 parent ec8e0a1 commit 73c13cc
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 11 deletions.
8 changes: 5 additions & 3 deletions planner/core/hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,21 +247,23 @@ func extractTableAsName(p PhysicalPlan) (*model.CIStr, *model.CIStr) {

func getJoinHints(sctx sessionctx.Context, joinType string, parentOffset int, nodeType nodeType, children ...PhysicalPlan) (res []*ast.TableOptimizerHint) {
for _, child := range children {
if child.SelectBlockOffset() == -1 {
blockOffset := child.SelectBlockOffset()
if blockOffset == -1 {
continue
}
var dbName, tableName *model.CIStr
if child.SelectBlockOffset() != parentOffset {
hintTable := sctx.GetSessionVars().PlannerSelectBlockAsName[child.SelectBlockOffset()]
dbName, tableName = &hintTable.DBName, &hintTable.TableName
// For sub-queries like `(select * from t) t1`, t1 should belong to its surrounding select block.
dbName, tableName, blockOffset = &hintTable.DBName, &hintTable.TableName, parentOffset
} else {
dbName, tableName = extractTableAsName(child)
}
if tableName == nil {
continue
}
res = append(res, &ast.TableOptimizerHint{
QBName: generateQBName(nodeType, child.SelectBlockOffset()),
QBName: generateQBName(nodeType, blockOffset),
HintName: model.NewCIStr(joinType),
Tables: []ast.HintTable{{DBName: *dbName, TableName: *tableName}},
})
Expand Down
23 changes: 16 additions & 7 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@ func (b *PlanBuilder) buildResultSetNode(ctx context.Context, node ast.ResultSet
case *ast.Join:
return b.buildJoin(ctx, x)
case *ast.TableSource:
var isTableName bool
switch v := x.Source.(type) {
case *ast.SelectStmt:
p, err = b.buildSelect(ctx, v)
case *ast.UnionStmt:
p, err = b.buildUnion(ctx, v)
case *ast.TableName:
p, err = b.buildDataSource(ctx, v, &x.AsName)
isTableName = true
default:
err = ErrUnsupportedType.GenWithStackByArgs(v)
}
Expand All @@ -196,7 +198,8 @@ func (b *PlanBuilder) buildResultSetNode(ctx context.Context, node ast.ResultSet
name.TblName = x.AsName
}
}
if b.ctx.GetSessionVars().PlannerSelectBlockAsName != nil {
// `TableName` is not a select block, so we do not need to handle it.
if !isTableName && b.ctx.GetSessionVars().PlannerSelectBlockAsName != nil {
b.ctx.GetSessionVars().PlannerSelectBlockAsName[p.SelectBlockOffset()] = ast.HintTable{DBName: p.OutputNames()[0].DBName, TableName: p.OutputNames()[0].TblName}
}
// Duplicate column name in one table is not allowed.
Expand Down Expand Up @@ -345,15 +348,21 @@ func (p *LogicalJoin) extractOnCondition(conditions []expression.Expression, der
// extractTableAlias returns table alias of the LogicalPlan's columns.
// It will return nil when there are multiple table alias, because the alias is only used to check if
// the logicalPlan match some optimizer hints, and hints are not expected to take effect in this case.
func extractTableAlias(p Plan) *hintTableInfo {
func extractTableAlias(p Plan, parentOffset int) *hintTableInfo {
if len(p.OutputNames()) > 0 && p.OutputNames()[0].TblName.L != "" {
firstName := p.OutputNames()[0]
for _, name := range p.OutputNames() {
if name.TblName.L != firstName.TblName.L || name.DBName.L != firstName.DBName.L {
return nil
}
}
return &hintTableInfo{dbName: firstName.DBName, tblName: firstName.TblName, selectOffset: p.SelectBlockOffset()}
blockOffset := p.SelectBlockOffset()
blockAsNames := p.SCtx().GetSessionVars().PlannerSelectBlockAsName
// For sub-queries like `(select * from t) t1`, t1 should belong to its surrounding select block.
if blockOffset != parentOffset && blockAsNames != nil && blockAsNames[blockOffset].TableName.L != "" {
blockOffset = parentOffset
}
return &hintTableInfo{dbName: firstName.DBName, tblName: firstName.TblName, selectOffset: blockOffset}
}
return nil
}
Expand All @@ -363,8 +372,8 @@ func (p *LogicalJoin) setPreferredJoinType(hintInfo *tableHintInfo) {
return
}

lhsAlias := extractTableAlias(p.children[0])
rhsAlias := extractTableAlias(p.children[1])
lhsAlias := extractTableAlias(p.children[0], p.blockOffset)
rhsAlias := extractTableAlias(p.children[1], p.blockOffset)
if hintInfo.ifPreferMergeJoin(lhsAlias, rhsAlias) {
p.preferJoinType |= preferMergeJoin
}
Expand Down Expand Up @@ -2782,8 +2791,8 @@ func (b *PlanBuilder) buildSemiJoin(outerPlan, innerPlan LogicalPlan, onConditio
}
// Apply forces to choose hash join currently, so don't worry the hints will take effect if the semi join is in one apply.
if b.TableHints() != nil {
outerAlias := extractTableAlias(outerPlan)
innerAlias := extractTableAlias(innerPlan)
outerAlias := extractTableAlias(outerPlan, joinPlan.blockOffset)
innerAlias := extractTableAlias(innerPlan, joinPlan.blockOffset)
if b.TableHints().ifPreferMergeJoin(outerAlias, innerAlias) {
joinPlan.preferJoinType |= preferMergeJoin
}
Expand Down
4 changes: 3 additions & 1 deletion planner/core/testdata/plan_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"select /*+ SM_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
"select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
"select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
"select /*+ HASH_JOIN(@sel_2 t1@sel_2, t2@sel_2), SM_JOIN(@sel_1 t1@sel_1, t2@sel_1) */ * from (select t1.a, t1.b from t t1, t t2 where t1.a = t2.a) t1, t t2 where t1.b = t2.b",
// aggregation hints
"select /*+ STREAM_AGG() */ s, count(s) from (select /*+ HASH_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s",
"select /*+ HASH_AGG() */ s, count(s) from (select /*+ STREAM_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s",
Expand Down Expand Up @@ -468,7 +469,8 @@
"select /*+ HASH_AGG(@sel_1), STREAM_AGG(@sel_2) */ count(*) from t t1 where t1.a < (select count(*) from t t2 where t1.a > t2.a)",
"select /*+ STREAM_AGG(@sel_1), HASH_AGG(@qb) */ count(*) from t t1 where t1.a < (select /*+ QB_NAME(qb) */ count(*) from t t2 where t1.a > t2.a)",
"select /*+ HASH_AGG(@sel_2) */ a, (select count(*) from t t1 where t1.b > t.a) from t where b > (select b from t t2 where t2.b = t.a limit 1)",
"select /*+ HASH_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t1) */ t1.b, t2.a, t2.aa from t t1, (select t1.a as a, t2.a as aa from t t1, t t2) t2 where t1.a = t2.aa;"
"select /*+ HASH_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t1) */ t1.b, t2.a, t2.aa from t t1, (select t1.a as a, t2.a as aa from t t1, t t2) t2 where t1.a = t2.aa;",
"select /*+ HASH_JOIN(@sel_2 t1@sel_2, t2@sel_2), SM_JOIN(@sel_1 t1@sel_1, t2@sel_1) */ * from (select t1.a, t1.b from t t1, t t2 where t1.a = t2.a) t1, t t2 where t1.b = t2.b"
]
},
{
Expand Down
9 changes: 9 additions & 0 deletions planner/core/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
"SQL": "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
"Best": "RightHashJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(Column#13,Column#27)}(Column#1,Column#13)->Projection"
},
{
"SQL": "select /*+ HASH_JOIN(@sel_2 t1@sel_2, t2@sel_2), SM_JOIN(@sel_1 t1@sel_1, t2@sel_1) */ * from (select t1.a, t1.b from t t1, t t2 where t1.a = t2.a) t1, t t2 where t1.b = t2.b",
"Best": "MergeInnerJoin{LeftHashJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#1,Column#13)->Sort->TableReader(Table(t))->Sort}(Column#2,Column#28)->Projection"
},
{
"SQL": "select /*+ STREAM_AGG() */ s, count(s) from (select /*+ HASH_AGG() */ sum(t1.a) as s from t t1, t t2 where t1.a = t2.b group by t1.a) p group by s",
"Best": "LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->TableReader(Table(t))}(Column#1,Column#14)->Projection->HashAgg->Sort->StreamAgg->Projection"
Expand Down Expand Up @@ -1243,6 +1247,11 @@
"SQL": "select /*+ HASH_JOIN(@sel_1 t1), HASH_JOIN(@sel_2 t1) */ t1.b, t2.a, t2.aa from t t1, (select t1.a as a, t2.a as aa from t t1, t t2) t2 where t1.a = t2.aa;",
"Plan": "RightHashJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.f)[[NULL,+inf]])}}(Column#1,Column#25)->Projection",
"Hints": "USE_INDEX(@`sel_1` `test`.`t1` ), USE_INDEX(@`sel_2` `test`.`t1` `f`), USE_INDEX(@`sel_2` `test`.`t2` `f`), HASH_JOIN(@`sel_2` `test`.`t1`), HASH_JOIN(@`sel_1` `test`.`t1`)"
},
{
"SQL": "select /*+ HASH_JOIN(@sel_2 t1@sel_2, t2@sel_2), SM_JOIN(@sel_1 t1@sel_1, t2@sel_1) */ * from (select t1.a, t1.b from t t1, t t2 where t1.a = t2.a) t1, t t2 where t1.b = t2.b",
"Plan": "MergeInnerJoin{LeftHashJoin{TableReader(Table(t))->IndexReader(Index(t.f)[[NULL,+inf]])}(Column#1,Column#13)->Sort->TableReader(Table(t))->Sort}(Column#2,Column#28)->Projection",
"Hints": "USE_INDEX(@`sel_2` `test`.`t1` ), USE_INDEX(@`sel_2` `test`.`t2` `f`), HASH_JOIN(@`sel_2` `test`.`t1`), USE_INDEX(@`sel_1` `test`.`t2` ), SM_JOIN(@`sel_1` `test`.`t1`)"
}
]
},
Expand Down

0 comments on commit 73c13cc

Please sign in to comment.