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: correct block offset for table as names #12996

Merged
merged 8 commits into from
Nov 11, 2019
Next Next commit
planner: correct block offset for table as names
  • Loading branch information
alivxxx committed Oct 29, 2019
commit 5c6aaf070b2cd8d405a6427701e14c35f7748b81
8 changes: 5 additions & 3 deletions planner/core/hints.go
Original file line number Diff line number Diff line change
@@ -245,21 +245,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}},
})
27 changes: 18 additions & 9 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
@@ -171,13 +171,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)
}
@@ -190,7 +192,8 @@ func (b *PlanBuilder) buildResultSetNode(ctx context.Context, node ast.ResultSet
col.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.Schema().Columns[0].DBName, TableName: p.Schema().Columns[0].TblName}
}
// Duplicate column name in one table is not allowed.
@@ -339,15 +342,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 p.Schema().Len() > 0 && p.Schema().Columns[0].TblName.L != "" {
firstCol := p.Schema().Columns[0]
for _, column := range p.Schema().Columns {
if column.TblName.L != firstCol.TblName.L || column.DBName.L != firstCol.DBName.L {
return nil
}
}
return &hintTableInfo{dbName: firstCol.DBName, tblName: firstCol.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: firstCol.DBName, tblName: firstCol.TblName, selectOffset: blockOffset}
}
return nil
}
@@ -357,8 +366,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
}
@@ -2677,8 +2686,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
}
@@ -2990,7 +2999,7 @@ func (b *PlanBuilder) buildUpdateLists(
func extractTableAsNameForUpdate(p LogicalPlan, asNames map[*model.TableInfo][]*model.CIStr) {
switch x := p.(type) {
case *DataSource:
alias := extractTableAlias(p)
alias := extractTableAlias(p, p.SelectBlockOffset())
if alias != nil {
if _, ok := asNames[x.tableInfo]; !ok {
asNames[x.tableInfo] = make([]*model.CIStr, 0, 1)
@@ -3013,7 +3022,7 @@ func extractTableAsNameForUpdate(p LogicalPlan, asNames map[*model.TableInfo][]*
return
}

alias := extractTableAlias(x)
alias := extractTableAlias(x, p.SelectBlockOffset())
if alias != nil {
if _, ok := asNames[ds.tableInfo]; !ok {
asNames[ds.tableInfo] = make([]*model.CIStr, 0, 1)
4 changes: 3 additions & 1 deletion planner/core/testdata/plan_suite_in.json
Original file line number Diff line number Diff line change
@@ -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",
@@ -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"
]
},
{
9 changes: 9 additions & 0 deletions planner/core/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
@@ -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"
@@ -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`)"
}
]
},