diff --git a/planner/core/casetest/rule/BUILD.bazel b/planner/core/casetest/rule/BUILD.bazel index 50d121108f1d1..7949277ddcb3b 100644 --- a/planner/core/casetest/rule/BUILD.bazel +++ b/planner/core/casetest/rule/BUILD.bazel @@ -12,7 +12,7 @@ go_test( ], data = glob(["testdata/**"]), flaky = True, - shard_count = 22, + shard_count = 23, deps = [ "//domain", "//expression", diff --git a/planner/core/casetest/rule/rule_join_reorder_test.go b/planner/core/casetest/rule/rule_join_reorder_test.go index aa3c49eae8cfb..5701fcae99279 100644 --- a/planner/core/casetest/rule/rule_join_reorder_test.go +++ b/planner/core/casetest/rule/rule_join_reorder_test.go @@ -83,6 +83,18 @@ func TestNoMergeJoinHint(t *testing.T) { runJoinReorderTestData(t, tk, "TestNoMergeJoinHint") } +func TestNoIndexJoinHint(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec(`set tidb_enable_index_merge_join=true`) + tk.MustExec("use test") + tk.MustExec("create table t1(a int, key(a));") + tk.MustExec("create table t2(a int, key(a));") + tk.MustExec("create table t3(a int, key(a));") + tk.MustExec("create table t4(a int, key(a));") + runJoinReorderTestData(t, tk, "TestNoIndexJoinHint") +} + func TestLeadingJoinHint(t *testing.T) { store := testkit.CreateMockStore(t) diff --git a/planner/core/casetest/rule/testdata/join_reorder_suite_in.json b/planner/core/casetest/rule/testdata/join_reorder_suite_in.json index 9c3bdf93492f8..1201331e17a43 100644 --- a/planner/core/casetest/rule/testdata/join_reorder_suite_in.json +++ b/planner/core/casetest/rule/testdata/join_reorder_suite_in.json @@ -49,6 +49,22 @@ "select /*+ leading(t1, t2, t3, t4), hash_join(t1, t2), no_hash_join(t3), hash_join(t4) */ * from t1, t2, t3, t4" ] }, + { + "name": "TestNoIndexJoinHint", + "cases": [ + "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1), no_index_merge_join(t2) */ * from t1, t2 where t1.a=t2.a", + "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1, t2), no_index_merge_join(t2, t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ no_merge_join(t1), no_hash_join(t1), inl_join(t1), no_index_merge_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ inl_join(t1), no_index_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ inl_hash_join(t1), no_index_hash_join(t2) */ * from t1, t2 where t1.a=t2.a", + "select /*+ inl_merge_join(t1), no_index_merge_join(t1, t2) */ * from t1, t2 where t1.a=t2.a", + "select /*+ inl_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "select /*+ inl_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a" + ] + }, { "name": "TestNoMergeJoinHint", "cases": [ diff --git a/planner/core/casetest/rule/testdata/join_reorder_suite_out.json b/planner/core/casetest/rule/testdata/join_reorder_suite_out.json index a057b18caebf0..fd4c581d478ee 100644 --- a/planner/core/casetest/rule/testdata/join_reorder_suite_out.json +++ b/planner/core/casetest/rule/testdata/join_reorder_suite_out.json @@ -782,6 +782,149 @@ } ] }, + { + "Name": "TestNoIndexJoinHint", + "Cases": [ + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t1.a, inner key:test.t2.a, equal cond:eq(test.t1.a, test.t2.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t2.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t2, index:a(a) range: decided by [eq(test.t2.a, test.t1.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1), no_index_merge_join(t2) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t1.a, inner key:test.t2.a, equal cond:eq(test.t1.a, test.t2.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t2.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t2, index:a(a) range: decided by [eq(test.t2.a, test.t1.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_hash_join(t1, t2), no_index_merge_join(t2, t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t1.a, inner key:test.t2.a, equal cond:eq(test.t1.a, test.t2.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t2.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t2, index:a(a) range: decided by [eq(test.t2.a, test.t1.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexHashJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t1.a, inner key:test.t2.a, equal cond:eq(test.t1.a, test.t2.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t2.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t2, index:a(a) range: decided by [eq(test.t2.a, test.t1.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), no_index_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexMergeJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t1.a, inner key:test.t2.a", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t2.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t2, index:a(a) range: decided by [eq(test.t2.a, test.t1.a)], keep order:true, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ no_merge_join(t1), no_hash_join(t1), inl_join(t1), no_index_merge_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a, equal cond:eq(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ inl_join(t1), no_index_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a, equal cond:eq(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Warning": [ + "Warning 1815 Some INL_JOIN and NO_INDEX_JOIN hints conflict, NO_INDEX_JOIN may be ignored" + ] + }, + { + "SQL": "select /*+ inl_hash_join(t1), no_index_hash_join(t2) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexHashJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a, equal cond:eq(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Warning": [ + "Warning 1815 Some INL_HASH_JOIN and NO_INDEX_HASH_JOIN hints conflict, NO_INDEX_HASH_JOIN may be ignored" + ] + }, + { + "SQL": "select /*+ inl_merge_join(t1), no_index_merge_join(t1, t2) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexMergeJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:true, stats:pseudo" + ], + "Warning": [ + "Warning 1815 Some INL_MERGE_JOIN and NO_INDEX_MERGE_JOIN hints conflict, NO_INDEX_MERGE_JOIN may be ignored" + ] + }, + { + "SQL": "select /*+ inl_join(t1), no_index_hash_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a, equal cond:eq(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Warning": null + }, + { + "SQL": "select /*+ inl_join(t1), no_index_merge_join(t1) */ * from t1, t2 where t1.a=t2.a", + "Plan": [ + "IndexJoin 12487.50 root inner join, inner:IndexReader, outer key:test.t2.a, inner key:test.t1.a, equal cond:eq(test.t2.a, test.t1.a)", + "├─IndexReader(Build) 9990.00 root index:IndexFullScan", + "│ └─IndexFullScan 9990.00 cop[tikv] table:t2, index:a(a) keep order:false, stats:pseudo", + "└─IndexReader(Probe) 12487.50 root index:Selection", + " └─Selection 12487.50 cop[tikv] not(isnull(test.t1.a))", + " └─IndexRangeScan 12500.00 cop[tikv] table:t1, index:a(a) range: decided by [eq(test.t1.a, test.t2.a)], keep order:false, stats:pseudo" + ], + "Warning": null + } + ] + }, { "Name": "TestNoMergeJoinHint", "Cases": [ diff --git a/planner/core/exhaust_physical_plans.go b/planner/core/exhaust_physical_plans.go index f984f2e12b2cc..3d4488f3c421e 100644 --- a/planner/core/exhaust_physical_plans.go +++ b/planner/core/exhaust_physical_plans.go @@ -2030,15 +2030,48 @@ func (p *LogicalJoin) tryToGetIndexJoin(prop *property.PhysicalProperty) (indexJ candidates = append(candidates, p.getIndexJoinByOuterIdx(prop, 1)...) } - // handle hints and variables about index join. - // the priority is: force hints like TIDB_INLJ > filter hints like NO_INDEX_JOIN > variables. + // Handle hints and variables about index join. + // The priority is: force hints like TIDB_INLJ > filter hints like NO_INDEX_JOIN > variables. + // Handle hints conflict first. + stmtCtx := p.SCtx().GetSessionVars().StmtCtx + if p.preferAny(preferLeftAsINLJInner, preferRightAsINLJInner) && p.preferAny(preferNoIndexJoin) { + stmtCtx.AppendWarning(ErrInternal.GenWithStack("Some INL_JOIN and NO_INDEX_JOIN hints conflict, NO_INDEX_JOIN may be ignored")) + } + if p.preferAny(preferLeftAsINLHJInner, preferRightAsINLHJInner) && p.preferAny(preferNoIndexHashJoin) { + stmtCtx.AppendWarning(ErrInternal.GenWithStack("Some INL_HASH_JOIN and NO_INDEX_HASH_JOIN hints conflict, NO_INDEX_HASH_JOIN may be ignored")) + } + if p.preferAny(preferLeftAsINLMJInner, preferRightAsINLMJInner) && p.preferAny(preferNoIndexMergeJoin) { + stmtCtx.AppendWarning(ErrInternal.GenWithStack("Some INL_MERGE_JOIN and NO_INDEX_MERGE_JOIN hints conflict, NO_INDEX_MERGE_JOIN may be ignored")) + } + candidates, canForced = p.handleForceIndexJoinHints(prop, candidates) if canForced { return candidates, canForced } + candidates = p.handleFilterIndexJoinHints(candidates) return filterIndexJoinBySessionVars(p.SCtx(), candidates), false } +func (p *LogicalJoin) handleFilterIndexJoinHints(candidates []PhysicalPlan) []PhysicalPlan { + if !p.preferAny(preferNoIndexJoin, preferNoIndexHashJoin, preferNoIndexMergeJoin) { + return candidates // no filter index join hints + } + filtered := make([]PhysicalPlan, 0, len(candidates)) + for _, candidate := range candidates { + _, joinMethod, ok := p.getIndexJoinSideAndMethod(candidate) + if !ok { + continue + } + if (p.preferAny(preferNoIndexJoin) && joinMethod == indexJoinMethod) || + (p.preferAny(preferNoIndexHashJoin) && joinMethod == indexHashJoinMethod) || + (p.preferAny(preferNoIndexMergeJoin) && joinMethod == indexMergeJoinMethod) { + continue + } + filtered = append(filtered, candidate) + } + return filtered +} + // handleForceIndexJoinHints handles the force index join hints and returns all plans that can satisfy the hints. func (p *LogicalJoin) handleForceIndexJoinHints(prop *property.PhysicalProperty, candidates []PhysicalPlan) (indexJoins []PhysicalPlan, canForced bool) { if !p.preferAny(preferRightAsINLJInner, preferRightAsINLHJInner, preferRightAsINLMJInner, diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index f16cf42c36600..69a300e6e3372 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -98,6 +98,12 @@ const ( HintINLHJ = "inl_hash_join" // HintINLMJ is hint enforce index nested loop merge join. HintINLMJ = "inl_merge_join" + // HintNoIndexJoin is the hint to enforce the query not to use index join. + HintNoIndexJoin = "no_index_join" + // HintNoIndexHashJoin is the hint to enforce the query not to use index hash join. + HintNoIndexHashJoin = "no_index_hash_join" + // HintNoIndexMergeJoin is the hint to enforce the query not to use index merge join. + HintNoIndexMergeJoin = "no_index_merge_join" // TiDBHashJoin is hint enforce hash join. TiDBHashJoin = "tidb_hj" // HintNoHashJoin is the hint to enforce the query not to use hash join. @@ -794,6 +800,30 @@ func (p *LogicalJoin) setPreferredJoinTypeAndOrder(hintInfo *tableHintInfo) { p.preferJoinType |= preferRightAsINLMJInner p.rightPreferJoinType |= preferINLMJ } + if hintInfo.ifPreferNoIndexJoin(lhsAlias) { + p.preferJoinType |= preferNoIndexJoin + p.leftPreferJoinType |= preferNoIndexJoin + } + if hintInfo.ifPreferNoIndexJoin(rhsAlias) { + p.preferJoinType |= preferNoIndexJoin + p.rightPreferJoinType |= preferNoIndexJoin + } + if hintInfo.ifPreferNoIndexHashJoin(lhsAlias) { + p.preferJoinType |= preferNoIndexHashJoin + p.leftPreferJoinType |= preferNoIndexHashJoin + } + if hintInfo.ifPreferNoIndexHashJoin(rhsAlias) { + p.preferJoinType |= preferNoIndexHashJoin + p.rightPreferJoinType |= preferNoIndexHashJoin + } + if hintInfo.ifPreferNoIndexMergeJoin(lhsAlias) { + p.preferJoinType |= preferNoIndexMergeJoin + p.leftPreferJoinType |= preferNoIndexMergeJoin + } + if hintInfo.ifPreferNoIndexMergeJoin(rhsAlias) { + p.preferJoinType |= preferNoIndexMergeJoin + p.rightPreferJoinType |= preferNoIndexMergeJoin + } if hintInfo.ifPreferHJBuild(lhsAlias) { p.preferJoinType |= preferLeftAsHJBuild p.leftPreferJoinType |= preferHJBuild @@ -3971,6 +4001,7 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev hints = b.hintProcessor.GetCurrentStmtHints(hints, currentLevel) var ( sortMergeTables, inljTables, inlhjTables, inlmjTables, hashJoinTables, bcTables []hintTableInfo + noIndexJoinTables, noIndexHashJoinTables, noIndexMergeJoinTables []hintTableInfo noHashJoinTables, noMergeJoinTables []hintTableInfo shuffleJoinTables []hintTableInfo indexHintList, indexMergeHintList []indexHintInfo @@ -4013,6 +4044,12 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev noHashJoinTables = append(noHashJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...) case HintNoMergeJoin: noMergeJoinTables = append(noMergeJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...) + case HintNoIndexJoin: + noIndexJoinTables = append(noIndexJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...) + case HintNoIndexHashJoin: + noIndexHashJoinTables = append(noIndexHashJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...) + case HintNoIndexMergeJoin: + noIndexMergeJoinTables = append(noIndexMergeJoinTables, tableNames2HintTableInfo(b.ctx, hint.HintName.L, hint.Tables, b.hintProcessor, currentLevel)...) case HintMPP1PhaseAgg: aggHints.preferAggType |= preferMPP1PhaseAgg case HintMPP2PhaseAgg: @@ -4122,6 +4159,7 @@ func (b *PlanBuilder) pushTableHints(hints []*ast.TableOptimizerHint, currentLev broadcastJoinTables: bcTables, shuffleJoinTables: shuffleJoinTables, indexNestedLoopJoinTables: indexNestedLoopJoinTables{inljTables, inlhjTables, inlmjTables}, + noIndexJoinTables: indexNestedLoopJoinTables{noIndexJoinTables, noIndexHashJoinTables, noIndexMergeJoinTables}, hashJoinTables: hashJoinTables, noHashJoinTables: noHashJoinTables, noMergeJoinTables: noMergeJoinTables, @@ -7371,6 +7409,9 @@ func getInnerFromParenthesesAndUnaryPlus(expr ast.ExprNode) ast.ExprNode { func containDifferentJoinTypes(preferJoinType uint) bool { preferJoinType &= ^preferNoHashJoin preferJoinType &= ^preferNoMergeJoin + preferJoinType &= ^preferNoIndexJoin + preferJoinType &= ^preferNoIndexHashJoin + preferJoinType &= ^preferNoIndexMergeJoin inlMask := preferRightAsINLJInner ^ preferLeftAsINLJInner inlhjMask := preferRightAsINLHJInner ^ preferLeftAsINLHJInner diff --git a/planner/core/logical_plans.go b/planner/core/logical_plans.go index fc989e30e3561..104ef6b656fc9 100644 --- a/planner/core/logical_plans.go +++ b/planner/core/logical_plans.go @@ -125,6 +125,9 @@ const ( preferNoHashJoin preferMergeJoin preferNoMergeJoin + preferNoIndexJoin + preferNoIndexHashJoin + preferNoIndexMergeJoin preferBCJoin preferShuffleJoin preferRewriteSemiJoin diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index d0931463e01f8..f206287cce255 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -92,6 +92,7 @@ type indexNestedLoopJoinTables struct { type tableHintInfo struct { indexNestedLoopJoinTables + noIndexJoinTables indexNestedLoopJoinTables sortMergeJoinTables []hintTableInfo broadcastJoinTables []hintTableInfo shuffleJoinTables []hintTableInfo @@ -270,6 +271,18 @@ func (info *tableHintInfo) ifPreferINLMJ(tableNames ...*hintTableInfo) bool { return info.matchTableName(tableNames, info.indexNestedLoopJoinTables.inlmjTables) } +func (info *tableHintInfo) ifPreferNoIndexJoin(tableNames ...*hintTableInfo) bool { + return info.matchTableName(tableNames, info.noIndexJoinTables.inljTables) +} + +func (info *tableHintInfo) ifPreferNoIndexHashJoin(tableNames ...*hintTableInfo) bool { + return info.matchTableName(tableNames, info.noIndexJoinTables.inlhjTables) +} + +func (info *tableHintInfo) ifPreferNoIndexMergeJoin(tableNames ...*hintTableInfo) bool { + return info.matchTableName(tableNames, info.noIndexJoinTables.inlmjTables) +} + func (info *tableHintInfo) ifPreferTiFlash(tableName *hintTableInfo) *hintTableInfo { if tableName == nil { return nil