Skip to content

Commit 9373263

Browse files
committed
Changing how NO_MERGE_JOIN hint is applied to fix panic
1 parent cf1535b commit 9373263

File tree

4 files changed

+28
-52
lines changed

4 files changed

+28
-52
lines changed

sql/analyzer/indexed_joins.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ func replanJoin(ctx *sql.Context, n *plan.JoinNode, a *Analyzer, scope *plan.Sco
158158

159159
qFlags.Set(sql.QFlagInnerJoin)
160160

161+
m.SetDefaultHints()
162+
hints := memo.ExtractJoinHint(n)
163+
for _, h := range hints {
164+
m.ApplyHint(h)
165+
}
166+
161167
err = addIndexScans(ctx, m)
162168
if err != nil {
163169
return nil, err
@@ -180,9 +186,11 @@ func replanJoin(ctx *sql.Context, n *plan.JoinNode, a *Analyzer, scope *plan.Sco
180186
return nil, err
181187
}
182188

183-
err = addMergeJoins(ctx, m)
184-
if err != nil {
185-
return nil, err
189+
if !m.MergeJoinsDisabled() {
190+
err = addMergeJoins(ctx, m)
191+
if err != nil {
192+
return nil, err
193+
}
186194
}
187195

188196
memo.CardMemoGroups(ctx, m.Root())
@@ -200,14 +208,6 @@ func replanJoin(ctx *sql.Context, n *plan.JoinNode, a *Analyzer, scope *plan.Sco
200208
return nil, err
201209
}
202210

203-
m.SetDefaultHints()
204-
hints := memo.ExtractJoinHint(n)
205-
for _, h := range hints {
206-
// this should probably happen earlier, but the root is not
207-
// populated before reordering
208-
m.ApplyHint(h)
209-
}
210-
211211
err = m.OptimizeRoot()
212212
if err != nil {
213213
return nil, err

sql/memo/join_order_builder.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ var ErrUnsupportedReorderNode = errors.New("unsupported join reorder node")
154154

155155
// useFastReorder determines whether to skip the current brute force join planning and use an alternate
156156
// planning algorithm that analyzes the join tree to find a sequence that can be implemented purely as lookup joins.
157-
// Currently we only use it for large joins (20+ tables) with no join hints.
157+
// Currently, we only use it for large joins (15+ tables) with no join hints.
158158
func (j *joinOrderBuilder) useFastReorder() bool {
159159
if j.forceFastDFSLookupForTest {
160160
return true
@@ -180,7 +180,7 @@ func (j *joinOrderBuilder) ReorderJoin(n sql.Node) {
180180
// from ensureClosure in buildSingleLookupPlan, but the equivalence sets could create multiple possible join orders
181181
// for the single-lookup plan, which would complicate things.
182182
j.ensureClosure(j.m.root)
183-
j.dbSube()
183+
j.dpEnumerateSubsets()
184184
return
185185
}
186186

@@ -627,10 +627,10 @@ func (j *joinOrderBuilder) checkSize() {
627627
}
628628
}
629629

630-
// dpSube iterates all disjoint combinations of table sets,
630+
// dpEnumerateSubsets iterates all disjoint combinations of table sets,
631631
// adding plans to the tree when we find two sets that can
632632
// be joined
633-
func (j *joinOrderBuilder) dbSube() {
633+
func (j *joinOrderBuilder) dpEnumerateSubsets() {
634634
all := j.allVertices()
635635
for subset := vertexSet(1); subset <= all; subset++ {
636636
if subset.isSingleton() {

sql/memo/memo.go

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -465,11 +465,6 @@ func (m *Memo) optimizeMemoGroup(grp *ExprGroup) error {
465465
// rather than a local property.
466466
func (m *Memo) updateBest(grp *ExprGroup, n RelExpr, cost float64) {
467467
if !m.hints.isEmpty() {
468-
for _, block := range m.hints.block {
469-
if !block.isOk(n) {
470-
return
471-
}
472-
}
473468
if m.hints.satisfiedBy(n) {
474469
if !grp.HintOk {
475470
grp.Best = n
@@ -528,25 +523,11 @@ func (m *Memo) ApplyHint(hint Hint) {
528523
m.SetJoinOrder(hint.Args)
529524
case HintTypeJoinFixedOrder:
530525
case HintTypeNoMergeJoin:
531-
m.SetBlockOp(func(n RelExpr) bool {
532-
switch n := n.(type) {
533-
case JoinRel:
534-
jp := n.JoinPrivate()
535-
if !jp.Left.Best.Group().HintOk || !jp.Right.Best.Group().HintOk {
536-
// equiv closures can generate child plans that bypass hints
537-
return false
538-
}
539-
if jp.Op.IsMerge() {
540-
return false
541-
}
542-
}
543-
return true
544-
})
526+
m.hints.disableMergeJoin = true
545527
case HintTypeInnerJoin, HintTypeMergeJoin, HintTypeLookupJoin, HintTypeHashJoin, HintTypeSemiJoin, HintTypeAntiJoin, HintTypeLeftOuterLookupJoin:
546528
m.SetJoinOp(hint.Typ, hint.Args[0], hint.Args[1])
547529
case HintTypeLeftDeep:
548530
m.hints.leftDeep = true
549-
default:
550531
}
551532
}
552533

@@ -568,10 +549,6 @@ func (m *Memo) SetJoinOrder(tables []string) {
568549
}
569550
}
570551

571-
func (m *Memo) SetBlockOp(cb func(n RelExpr) bool) {
572-
m.hints.block = append(m.hints.block, joinBlockHint{cb: cb})
573-
}
574-
575552
func (m *Memo) SetJoinOp(op HintType, left, right string) {
576553
var lTab, rTab sql.TableId
577554
for _, n := range m.root.RelProps.TableIdNodes() {
@@ -592,6 +569,12 @@ func (m *Memo) SetJoinOp(op HintType, left, right string) {
592569
m.hints.ops = append(m.hints.ops, hint)
593570
}
594571

572+
// MergeJoinsDisabled returns true if a hint to disable merge joins has been set. If so, then the join planner
573+
// will not generate or cost any join plans that contain MergeJoin physical operators.
574+
func (m *Memo) MergeJoinsDisabled() bool {
575+
return m.hints.disableMergeJoin
576+
}
577+
595578
func (m *Memo) String() string {
596579
exprs := make([]string, m.cnt)
597580
groups := make([]*ExprGroup, 0)

sql/memo/select_hints.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,25 +372,18 @@ func (o joinOpHint) typeMatches(n RelExpr) bool {
372372
return true
373373
}
374374

375-
type joinBlockHint struct {
376-
cb func(n RelExpr) bool
377-
}
378-
379-
func (o joinBlockHint) isOk(n RelExpr) bool {
380-
return o.cb(n)
381-
}
382-
383375
// joinHints wraps a collection of join hints. The memo
384376
// interfaces with this object during costing.
385377
type joinHints struct {
386-
ops []joinOpHint
387-
order *joinOrderHint
388-
block []joinBlockHint
389-
leftDeep bool
378+
ops []joinOpHint
379+
order *joinOrderHint
380+
leftDeep bool
381+
disableMergeJoin bool
390382
}
391383

384+
// isEmpty returns true if no hints that affect join planning have been set.
392385
func (h joinHints) isEmpty() bool {
393-
return len(h.ops) == 0 && h.order == nil && !h.leftDeep && len(h.block) == 0
386+
return len(h.ops) == 0 && h.order == nil && !h.leftDeep && !h.disableMergeJoin
394387
}
395388

396389
// satisfiedBy returns whether a RelExpr satisfies every join hint. This

0 commit comments

Comments
 (0)