Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions pkg/planner/core/joinorder/join_order.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ func optimizeRecursive(p base.LogicalPlan) (base.LogicalPlan, error) {
}
if len(vertexMap) > 0 {
joinGroup.root = replaceJoinGroupVertexes(joinGroup.root, vertexMap)
if len(joinGroup.vertexHints) > 0 {
joinGroup.vertexHints = rebindVertexHints(joinGroup.vertexHints, vertexMap)
}
}
if p, err = optimizeForJoinGroup(p.SCtx(), joinGroup); err != nil {
return nil, err
Expand Down Expand Up @@ -313,6 +316,21 @@ func replaceJoinGroupVertexes(root base.LogicalPlan, vertexMap map[int]base.Logi
return root
}

func rebindVertexHints(vertexHints map[int]*JoinMethodHint, vertexMap map[int]base.LogicalPlan) map[int]*JoinMethodHint {
if len(vertexHints) == 0 || len(vertexMap) == 0 {
return vertexHints
}
rebuilt := make(map[int]*JoinMethodHint, len(vertexHints))
for oldID, hintInfo := range vertexHints {
if optimizedVertex, ok := vertexMap[oldID]; ok && ShouldRebindJoinMethodHint(hintInfo.PreferJoinMethod) {
rebuilt[optimizedVertex.ID()] = hintInfo
continue
}
rebuilt[oldID] = hintInfo
}
return rebuilt
}

func optimizeForJoinGroup(ctx base.PlanContext, group *joinGroup) (p base.LogicalPlan, err error) {
originalSchema := group.root.Schema()

Expand Down
8 changes: 8 additions & 0 deletions pkg/planner/core/joinorder/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ type JoinMethodHint struct {
HintInfo *hint.PlanHints
}

// ShouldRebindJoinMethodHint reports whether a join method hint should follow
// the optimized vertex ID after recursive subtree optimization.
func ShouldRebindJoinMethodHint(preferJoinMethod uint) bool {
indexJoinMask := hint.PreferINLJ | hint.PreferINLHJ | hint.PreferINLMJ |
hint.PreferNoIndexJoin | hint.PreferNoIndexHashJoin | hint.PreferNoIndexMergeJoin
return preferJoinMethod&indexJoinMask > 0
}

// CheckAndGenerateLeadingHint used to check and generate the valid leading hint.
// We are allowed to use at most one leading hint in a join group. When more than one,
// all leading hints in the current join group will be invalid.
Expand Down
58 changes: 58 additions & 0 deletions pkg/planner/core/physical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,64 @@ func TestJoinHintCompatibilityWithVariable(t *testing.T) {
tk.MustExec("select /*+ leading(t2), hash_join(t2) */ * from t t1 join t t2 join t t3 where t1.a = t2.a and t2.b = t3.b;")
res := tk.MustQuery("show warnings").Rows()
require.Equal(t, len(res) > 0, true)
tk.MustExec("drop table if exists table_insurant, table_house, table_role_connection")
tk.MustExec("create table table_insurant(actualid varchar(32), serialNo varchar(32), key idx_actualid(actualid))")
tk.MustExec("create table table_house(actualid varchar(32), planNo varchar(32), topId varchar(32), insurantNo varchar(32), key idx_actualid(actualid), key idx_insurantNo(insurantNo))")
tk.MustExec("create table table_role_connection(actualid varchar(32), parentId varchar(32), specid varchar(32), key idx_parent_spec_actual(parentId, specid, actualid), key idx_actualid(actualid))")

tk.MustExec(`insert into table_insurant values
('a1', '2'),
('a2', '3')`)
tk.MustExec(`insert into table_house values
('h1', 'p1', 't1', '2'),
('h2', 'p2', 't2', '9')`)
tk.MustExec(`insert into table_role_connection values
('a1', '3561703379345', '14535'),
('h1', '3561703379345', '14550')`)

sql := `explain select
count(*)
from
(
select /*+ inl_join(t1) */
t2.actualId,
t2.planNo,
t2.topId,
t2.insurantNo
from
(
select *
from table_insurant
where actualid in (
select actualid
from table_role_connection
where parentId = '3561703379345'
and specid = '14535'
)
) t1,
(
select *
from table_house
where actualid in (
select actualid
from table_role_connection
where parentId = '3561703379345'
and specid = '14550'
)
) t2
where t1.serialNo = t2.insurantNo
and t2.insurantNo = '2'
) s`

expectedWarn := "Warning 1815 Optimizer Hint /*+ INL_JOIN(t1) */ or /*+ TIDB_INLJ(t1) */ is inapplicable"

tk.MustExec("set @@session.tidb_opt_advanced_join_hint=0")
tk.MustQuery(sql).Rows()
tk.MustQuery("show warnings").Check(testkit.Rows(expectedWarn))

tk.MustExec("set @@session.tidb_opt_advanced_join_hint=1")
tk.MustQuery(sql).Rows()
tk.MustQuery("show warnings").Check(testkit.Rows(expectedWarn))
Comment thread
hawkingrei marked this conversation as resolved.
})
}

Expand Down
21 changes: 21 additions & 0 deletions pkg/planner/core/rule_join_reorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,17 @@ func (s *JoinReOrderSolver) optimizeRecursive(ctx base.PlanContext, p base.Logic
result := extractJoinGroup(p)
curJoinGroup, joinTypes, joinOrderHintInfo, hasOuterJoin := result.group, result.joinTypes, result.joinOrderHintInfo, result.hasOuterJoin
if len(curJoinGroup) > 1 {
optimizedVertexMap := make(map[int]base.LogicalPlan, len(curJoinGroup))
for i := range curJoinGroup {
oldID := curJoinGroup[i].ID()
curJoinGroup[i], err = s.optimizeRecursive(ctx, curJoinGroup[i])
if err != nil {
return nil, err
}
optimizedVertexMap[oldID] = curJoinGroup[i]
}
if len(result.joinMethodHintInfo) > 0 {
result.joinMethodHintInfo = rebindJoinMethodHints(result.joinMethodHintInfo, optimizedVertexMap)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
originalSchema := p.Schema()

Expand Down Expand Up @@ -403,6 +409,21 @@ func (s *JoinReOrderSolver) optimizeRecursive(ctx base.PlanContext, p base.Logic
return p, nil
}

func rebindJoinMethodHints(hints map[int]*joinorder.JoinMethodHint, optimizedVertexMap map[int]base.LogicalPlan) map[int]*joinorder.JoinMethodHint {
if len(hints) == 0 || len(optimizedVertexMap) == 0 {
return hints
}
rebuilt := make(map[int]*joinorder.JoinMethodHint, len(hints))
for oldID, hintInfo := range hints {
if optimizedVertex, ok := optimizedVertexMap[oldID]; ok && joinorder.ShouldRebindJoinMethodHint(hintInfo.PreferJoinMethod) {
rebuilt[optimizedVertex.ID()] = hintInfo
continue
}
rebuilt[oldID] = hintInfo
}
return rebuilt
}

// basicJoinGroupInfo represents basic information for a join group in the join reorder process.
type basicJoinGroupInfo struct {
eqEdges []*expression.ScalarFunction
Expand Down
Loading