Skip to content

Commit 2fc7dc9

Browse files
authored
Merge pull request #152349 from rytaft/backport25.2-151959
release-25.2: sql,opt: add session variable to disable optimizer rules (#152349)
2 parents 5361c4c + 2bcb65a commit 2fc7dc9

File tree

12 files changed

+237
-5
lines changed

12 files changed

+237
-5
lines changed

pkg/sql/exec_util.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"strings"
2121
"time"
2222

23-
apd "github.com/cockroachdb/apd/v3"
23+
"github.com/cockroachdb/apd/v3"
2424
"github.com/cockroachdb/cockroach/pkg/backup/backuppb"
2525
"github.com/cockroachdb/cockroach/pkg/base"
2626
"github.com/cockroachdb/cockroach/pkg/cloud/externalconn"
@@ -3850,6 +3850,10 @@ func (m *sessionDataMutator) SetTestingOptimizerDisableRuleProbability(val float
38503850
m.data.TestingOptimizerDisableRuleProbability = val
38513851
}
38523852

3853+
func (m *sessionDataMutator) SetDisableOptimizerRules(val []string) {
3854+
m.data.DisableOptimizerRules = val
3855+
}
3856+
38533857
func (m *sessionDataMutator) SetTrigramSimilarityThreshold(val float64) {
38543858
m.data.TrigramSimilarityThreshold = val
38553859
}

pkg/sql/logictest/testdata/logic_test/information_schema

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,6 +3943,7 @@ default_with_oids off
39433943
descriptor_validation on
39443944
disable_changefeed_replication off
39453945
disable_hoist_projection_in_join_limitation off
3946+
disable_optimizer_rules ·
39463947
disable_partially_distributed_plans off
39473948
disable_plan_gists off
39483949
disable_vec_union_eager_cancellation off

pkg/sql/logictest/testdata/logic_test/pg_catalog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2952,6 +2952,7 @@ default_with_oids off N
29522952
descriptor_validation on NULL NULL NULL string
29532953
disable_changefeed_replication off NULL NULL NULL string
29542954
disable_hoist_projection_in_join_limitation off NULL NULL NULL string
2955+
disable_optimizer_rules · NULL NULL NULL string
29552956
disable_partially_distributed_plans off NULL NULL NULL string
29562957
disable_plan_gists off NULL NULL NULL string
29572958
disable_vec_union_eager_cancellation off NULL NULL NULL string
@@ -3175,6 +3176,7 @@ default_with_oids off N
31753176
descriptor_validation on NULL user NULL on on
31763177
disable_changefeed_replication off NULL user NULL off off
31773178
disable_hoist_projection_in_join_limitation off NULL user NULL off off
3179+
disable_optimizer_rules · NULL user NULL · ·
31783180
disable_partially_distributed_plans off NULL user NULL off off
31793181
disable_plan_gists off NULL user NULL off off
31803182
disable_vec_union_eager_cancellation off NULL user NULL off off
@@ -3394,6 +3396,7 @@ descriptor_validation NULL NULL NULL
33943396
direct_columnar_scans_enabled NULL NULL NULL NULL NULL
33953397
disable_changefeed_replication NULL NULL NULL NULL NULL
33963398
disable_hoist_projection_in_join_limitation NULL NULL NULL NULL NULL
3399+
disable_optimizer_rules NULL NULL NULL NULL NULL
33973400
disable_partially_distributed_plans NULL NULL NULL NULL NULL
33983401
disable_plan_gists NULL NULL NULL NULL NULL
33993402
disable_vec_union_eager_cancellation NULL NULL NULL NULL NULL

pkg/sql/logictest/testdata/logic_test/show_source

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ default_with_oids off
6868
descriptor_validation on
6969
disable_changefeed_replication off
7070
disable_hoist_projection_in_join_limitation off
71+
disable_optimizer_rules ·
7172
disable_partially_distributed_plans off
7273
disable_plan_gists off
7374
disable_vec_union_eager_cancellation off
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# LogicTest: local
2+
3+
# Tests for the disable_optimizer_rules session variable.
4+
# This variable allows disabling specific optimizer rules by name.
5+
6+
statement ok
7+
CREATE TABLE t (a INT, b INT, c INT, INDEX (b))
8+
9+
# Basic test with the variable unset (default).
10+
query T
11+
EXPLAIN SELECT * FROM t WHERE b = 1
12+
----
13+
distribution: local
14+
vectorized: true
15+
·
16+
• index join
17+
│ table: t@t_pkey
18+
19+
└── • scan
20+
missing stats
21+
table: t@t_b_idx
22+
spans: [/1 - /1]
23+
24+
# Set the variable with a rule that doesn't affect this query.
25+
statement ok
26+
SET disable_optimizer_rules = 'PushFilterIntoJoinLeft'
27+
28+
# Query should still use the index.
29+
query T
30+
EXPLAIN SELECT * FROM t WHERE b = 1
31+
----
32+
distribution: local
33+
vectorized: true
34+
·
35+
• index join
36+
│ table: t@t_pkey
37+
38+
└── • scan
39+
missing stats
40+
table: t@t_b_idx
41+
spans: [/1 - /1]
42+
43+
# Set the variable to disable the rule to generate constrained scans.
44+
statement ok
45+
SET disable_optimizer_rules = 'GenerateConstrainedScans'
46+
47+
# Now the query should not use the index and instead use a full table scan.
48+
query T
49+
EXPLAIN SELECT * FROM t WHERE b = 1
50+
----
51+
distribution: local
52+
vectorized: true
53+
·
54+
• filter
55+
│ filter: b = 1
56+
57+
└── • scan
58+
missing stats
59+
table: t@t_pkey
60+
spans: FULL SCAN
61+
62+
# Test with multiple rules.
63+
statement ok
64+
SET disable_optimizer_rules = 'GenerateConstrainedScans,PushFilterIntoJoinLeft'
65+
66+
query T
67+
SHOW disable_optimizer_rules
68+
----
69+
GenerateConstrainedScans, PushFilterIntoJoinLeft
70+
71+
# The query should still not use the index.
72+
query T
73+
EXPLAIN SELECT * FROM t WHERE b = 1
74+
----
75+
distribution: local
76+
vectorized: true
77+
·
78+
• filter
79+
│ filter: b = 1
80+
81+
└── • scan
82+
missing stats
83+
table: t@t_pkey
84+
spans: FULL SCAN
85+
86+
# Test with non-existent rule (should generate a notice to the client).
87+
# Spaces should be trimmed so the other rule should still take effect.
88+
# The rules are case-insensitive, so generateConstrainedScans is equivalent
89+
# to GenerateConstrainedScans.
90+
statement notice NOTICE: rule NonExistentRule does not exist and will be ignored
91+
SET disable_optimizer_rules = 'NonExistentRule, generateConstrainedScans'
92+
93+
query T
94+
SHOW disable_optimizer_rules
95+
----
96+
generateConstrainedScans
97+
98+
# The query should still not use the index.
99+
query T
100+
EXPLAIN SELECT * FROM t WHERE b = 1
101+
----
102+
distribution: local
103+
vectorized: true
104+
·
105+
• filter
106+
│ filter: b = 1
107+
108+
└── • scan
109+
missing stats
110+
table: t@t_pkey
111+
spans: FULL SCAN
112+
113+
# Reset the variable.
114+
statement ok
115+
RESET disable_optimizer_rules
116+
117+
# Query should use the index again.
118+
query T
119+
EXPLAIN SELECT * FROM t WHERE b = 1
120+
----
121+
distribution: local
122+
vectorized: true
123+
·
124+
• index join
125+
│ table: t@t_pkey
126+
127+
└── • scan
128+
missing stats
129+
table: t@t_b_idx
130+
spans: [/1 - /1]
131+
132+
# Cleanup.
133+
statement ok
134+
DROP TABLE t

pkg/sql/opt/exec/execbuilder/tests/local/generated_test.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/opt/memo/memo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package memo
99
import (
1010
"bytes"
1111
"context"
12+
"reflect"
1213

1314
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/isolation"
1415
"github.com/cockroachdb/cockroach/pkg/sql/opt"
@@ -167,6 +168,7 @@ type Memo struct {
167168
testingOptimizerRandomSeed int64
168169
testingOptimizerCostPerturbation float64
169170
testingOptimizerDisableRuleProbability float64
171+
disableOptimizerRules []string
170172
enforceHomeRegion bool
171173
variableInequalityLookupJoinEnabled bool
172174
allowOrdinalColumnReferences bool
@@ -271,6 +273,7 @@ func (m *Memo) Init(ctx context.Context, evalCtx *eval.Context) {
271273
testingOptimizerRandomSeed: evalCtx.SessionData().TestingOptimizerRandomSeed,
272274
testingOptimizerCostPerturbation: evalCtx.SessionData().TestingOptimizerCostPerturbation,
273275
testingOptimizerDisableRuleProbability: evalCtx.SessionData().TestingOptimizerDisableRuleProbability,
276+
disableOptimizerRules: evalCtx.SessionData().DisableOptimizerRules,
274277
enforceHomeRegion: evalCtx.SessionData().EnforceHomeRegion,
275278
variableInequalityLookupJoinEnabled: evalCtx.SessionData().VariableInequalityLookupJoinEnabled,
276279
allowOrdinalColumnReferences: evalCtx.SessionData().AllowOrdinalColumnReferences,
@@ -448,6 +451,7 @@ func (m *Memo) IsStale(
448451
m.testingOptimizerRandomSeed != evalCtx.SessionData().TestingOptimizerRandomSeed ||
449452
m.testingOptimizerCostPerturbation != evalCtx.SessionData().TestingOptimizerCostPerturbation ||
450453
m.testingOptimizerDisableRuleProbability != evalCtx.SessionData().TestingOptimizerDisableRuleProbability ||
454+
!reflect.DeepEqual(m.disableOptimizerRules, evalCtx.SessionData().DisableOptimizerRules) ||
451455
m.enforceHomeRegion != evalCtx.SessionData().EnforceHomeRegion ||
452456
m.variableInequalityLookupJoinEnabled != evalCtx.SessionData().VariableInequalityLookupJoinEnabled ||
453457
m.allowOrdinalColumnReferences != evalCtx.SessionData().AllowOrdinalColumnReferences ||

pkg/sql/opt/memo/memo_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,12 @@ func TestMemoIsStale(t *testing.T) {
373373
evalCtx.SessionData().TestingOptimizerDisableRuleProbability = 0
374374
notStale()
375375

376+
// Stale disable_optimizer_rules.
377+
evalCtx.SessionData().DisableOptimizerRules = []string{"some_rule"}
378+
stale()
379+
evalCtx.SessionData().DisableOptimizerRules = nil
380+
notStale()
381+
376382
// Stale allow_ordinal_column_references.
377383
evalCtx.SessionData().AllowOrdinalColumnReferences = true
378384
stale()

pkg/sql/opt/rule_name.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55

66
package opt
77

8+
import "strings"
9+
10+
// RuleNameMap is a map from lower-case rule name strings to RuleName values.
11+
var RuleNameMap = make(map[string]RuleName, NumRuleNames)
12+
13+
func init() {
14+
for i := RuleName(1); i < NumRuleNames; i++ {
15+
if i == startAutoRule || i == startExploreRule {
16+
// Skip these markers.
17+
continue
18+
}
19+
RuleNameMap[strings.ToLower(i.String())] = i
20+
}
21+
}
22+
823
// RuleName enumerates the names of all the optimizer rules. Manual rule names
924
// are defined in this file and rule names generated by Optgen are defined in
1025
// rule_name.og.go.

pkg/sql/opt/xform/optimizer.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package xform
88
import (
99
"context"
1010
"math/rand"
11+
"strings"
1112

1213
"github.com/cockroachdb/cockroach/pkg/sql/opt"
1314
"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
@@ -133,6 +134,16 @@ func (o *Optimizer) Init(ctx context.Context, evalCtx *eval.Context, catalog cat
133134
o.mem = o.f.Memo()
134135
o.explorer.init(o)
135136

137+
var disabledRules RuleSet
138+
// If the DisableOptimizerRules session variable is set, then disable
139+
// the specified rules.
140+
if ruleNames := evalCtx.SessionData().DisableOptimizerRules; len(ruleNames) > 0 {
141+
for _, ruleName := range ruleNames {
142+
if rule, ok := opt.RuleNameMap[strings.ToLower(ruleName)]; ok {
143+
disabledRules.Add(int(rule))
144+
}
145+
}
146+
}
136147
if seed := evalCtx.SessionData().TestingOptimizerRandomSeed; seed != 0 {
137148
o.rng = rand.New(rand.NewSource(seed))
138149
}
@@ -153,7 +164,10 @@ func (o *Optimizer) Init(ctx context.Context, evalCtx *eval.Context, catalog cat
153164
o.defaultCoster.Init(ctx, evalCtx, o.mem, costPerturbation, o.rng, o)
154165
o.coster = &o.defaultCoster
155166
if disableRuleProbability > 0 {
156-
o.disableRulesRandom(disableRuleProbability)
167+
o.disableRulesRandom(disableRuleProbability, &disabledRules)
168+
}
169+
if disabledRules.Len() > 0 {
170+
o.disableRules(disabledRules)
157171
}
158172
}
159173

@@ -1067,7 +1081,7 @@ func (a *groupStateAlloc) allocate() *groupState {
10671081
}
10681082

10691083
// disableRulesRandom disables rules with the given probability for testing.
1070-
func (o *Optimizer) disableRulesRandom(probability float64) {
1084+
func (o *Optimizer) disableRulesRandom(probability float64, disabledRules *RuleSet) {
10711085
essentialRules := intsets.MakeFast(
10721086
// Needed to prevent constraint building from failing.
10731087
int(opt.NormalizeInConst),
@@ -1115,7 +1129,6 @@ func (o *Optimizer) disableRulesRandom(probability float64) {
11151129
int(opt.ConvertUncorrelatedExistsToCoalesceSubquery),
11161130
)
11171131

1118-
var disabledRules RuleSet
11191132
for i := opt.RuleName(1); i < opt.NumRuleNames; i++ {
11201133
var r float64
11211134
if o.rng == nil {
@@ -1127,12 +1140,14 @@ func (o *Optimizer) disableRulesRandom(probability float64) {
11271140
disabledRules.Add(int(i))
11281141
}
11291142
}
1143+
}
11301144

1145+
func (o *Optimizer) disableRules(disabledRules RuleSet) {
11311146
o.f.SetDisabledRules(disabledRules)
11321147

11331148
o.NotifyOnMatchedRule(func(ruleName opt.RuleName) bool {
11341149
if disabledRules.Contains(int(ruleName)) {
1135-
log.Infof(o.ctx, "disabled rule matched: %s", ruleName.String())
1150+
log.VEventf(o.ctx, 2, "disabled rule matched: %s", ruleName.String())
11361151
return false
11371152
}
11381153
return true

0 commit comments

Comments
 (0)