Skip to content

Commit 526e15f

Browse files
committed
opt: add optimizer_min_row_count session setting
Informs #64570 Informs #130201 Release note (sql change): The `optimizer_min_row_count` session setting has been added which sets a lower bound on row count estimates for relational expressions during query planning. A value of zero, which is the default, indicates no lower bound. Note that if this is set to a value greater than zero, a row count of zero can still be estimated for expressions with a cardinality of zero, e.g., for a contradictory filter. Setting this to a value higher than 0, such as 1, may yield better query plans in some cases, such as when statistics are frequently stale and inaccurate.
1 parent 64bad8e commit 526e15f

File tree

20 files changed

+313
-70
lines changed

20 files changed

+313
-70
lines changed

Diff for: pkg/sql/exec_util.go

+4
Original file line numberDiff line numberDiff line change
@@ -4011,6 +4011,10 @@ func (m *sessionDataMutator) SetOptimizerPreferBoundedCardinality(b bool) {
40114011
m.data.OptimizerPreferBoundedCardinality = b
40124012
}
40134013

4014+
func (m *sessionDataMutator) SetOptimizerMinRowCount(val float64) {
4015+
m.data.OptimizerMinRowCount = val
4016+
}
4017+
40144018
// Utility functions related to scrubbing sensitive information on SQL Stats.
40154019

40164020
// quantizeCounts ensures that the Count field in the

Diff for: pkg/sql/logictest/testdata/logic_test/information_schema

+1
Original file line numberDiff line numberDiff line change
@@ -4007,6 +4007,7 @@ optimizer on
40074007
optimizer_always_use_histograms on
40084008
optimizer_hoist_uncorrelated_equality_subqueries on
40094009
optimizer_merge_joins_enabled on
4010+
optimizer_min_row_count 0
40104011
optimizer_prefer_bounded_cardinality off
40114012
optimizer_prove_implication_with_virtual_computed_columns on
40124013
optimizer_push_limit_into_project_filtered_scan on

Diff for: pkg/sql/logictest/testdata/logic_test/pg_catalog

+3
Original file line numberDiff line numberDiff line change
@@ -3007,6 +3007,7 @@ opt_split_scan_limit 2048 N
30073007
optimizer_always_use_histograms on NULL NULL NULL string
30083008
optimizer_hoist_uncorrelated_equality_subqueries on NULL NULL NULL string
30093009
optimizer_merge_joins_enabled on NULL NULL NULL string
3010+
optimizer_min_row_count 0 NULL NULL NULL string
30103011
optimizer_prefer_bounded_cardinality off NULL NULL NULL string
30113012
optimizer_prove_implication_with_virtual_computed_columns on NULL NULL NULL string
30123013
optimizer_push_limit_into_project_filtered_scan on NULL NULL NULL string
@@ -3213,6 +3214,7 @@ opt_split_scan_limit 2048 N
32133214
optimizer_always_use_histograms on NULL user NULL on on
32143215
optimizer_hoist_uncorrelated_equality_subqueries on NULL user NULL on on
32153216
optimizer_merge_joins_enabled on NULL user NULL on on
3217+
optimizer_min_row_count 0 NULL user NULL 0 0
32163218
optimizer_prefer_bounded_cardinality off NULL user NULL off off
32173219
optimizer_prove_implication_with_virtual_computed_columns on NULL user NULL on on
32183220
optimizer_push_limit_into_project_filtered_scan on NULL user NULL on on
@@ -3418,6 +3420,7 @@ optimizer NULL NULL NULL
34183420
optimizer_always_use_histograms NULL NULL NULL NULL NULL
34193421
optimizer_hoist_uncorrelated_equality_subqueries NULL NULL NULL NULL NULL
34203422
optimizer_merge_joins_enabled NULL NULL NULL NULL NULL
3423+
optimizer_min_row_count NULL NULL NULL NULL NULL
34213424
optimizer_prefer_bounded_cardinality NULL NULL NULL NULL NULL
34223425
optimizer_prove_implication_with_virtual_computed_columns NULL NULL NULL NULL NULL
34233426
optimizer_push_limit_into_project_filtered_scan NULL NULL NULL NULL NULL

Diff for: pkg/sql/logictest/testdata/logic_test/show_source

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ opt_split_scan_limit 2048
138138
optimizer_always_use_histograms on
139139
optimizer_hoist_uncorrelated_equality_subqueries on
140140
optimizer_merge_joins_enabled on
141+
optimizer_min_row_count 0
141142
optimizer_prefer_bounded_cardinality off
142143
optimizer_prove_implication_with_virtual_computed_columns on
143144
optimizer_push_limit_into_project_filtered_scan on

Diff for: pkg/sql/opt/exec/execbuilder/testdata/explain_redact

+5-5
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ upsert bc
678678
query T
679679
EXPLAIN (OPT, MEMO, REDACT) INSERT INTO bc SELECT a::float + 1 FROM a ON CONFLICT (b) DO UPDATE SET b = bc.b + 100
680680
----
681-
memo (optimized, ~36KB, required=[presentation: info:25] [distribution: test])
681+
memo (optimized, ~37KB, required=[presentation: info:25] [distribution: test])
682682
├── G1: (explain G2 [distribution: test])
683683
│ └── [presentation: info:25] [distribution: test]
684684
│ ├── best: (explain G2="[distribution: test]" [distribution: test])
@@ -1117,7 +1117,7 @@ update ab
11171117
query T
11181118
EXPLAIN (OPT, MEMO, REDACT) UPDATE ab SET a = a || 'ab' WHERE a > 'a'
11191119
----
1120-
memo (optimized, ~14KB, required=[presentation: info:15] [distribution: test])
1120+
memo (optimized, ~15KB, required=[presentation: info:15] [distribution: test])
11211121
├── G1: (explain G2 [distribution: test])
11221122
│ └── [presentation: info:15] [distribution: test]
11231123
│ ├── best: (explain G2="[distribution: test]" [distribution: test])
@@ -1355,7 +1355,7 @@ update e
13551355
query T
13561356
EXPLAIN (OPT, MEMO, REDACT) UPDATE e SET e = 'eee' WHERE e > 'a'
13571357
----
1358-
memo (optimized, ~17KB, required=[presentation: info:17] [distribution: test])
1358+
memo (optimized, ~18KB, required=[presentation: info:17] [distribution: test])
13591359
├── G1: (explain G2 [distribution: test])
13601360
│ └── [presentation: info:17] [distribution: test]
13611361
│ ├── best: (explain G2="[distribution: test]" [distribution: test])
@@ -1686,7 +1686,7 @@ project
16861686
query T
16871687
EXPLAIN (OPT, MEMO, REDACT) SELECT * FROM bc WHERE b >= 1.0 AND b < 2.0
16881688
----
1689-
memo (optimized, ~12KB, required=[presentation: info:7] [distribution: test])
1689+
memo (optimized, ~13KB, required=[presentation: info:7] [distribution: test])
16901690
├── G1: (explain G2 [presentation: b:1,c:2] [distribution: test])
16911691
│ └── [presentation: info:7] [distribution: test]
16921692
│ ├── best: (explain G2="[presentation: b:1,c:2] [distribution: test]" [presentation: b:1,c:2] [distribution: test])
@@ -2435,7 +2435,7 @@ project
24352435
query T
24362436
EXPLAIN (OPT, MEMO, REDACT) SELECT * FROM bc JOIN f ON b = f + 1
24372437
----
2438-
memo (optimized, ~28KB, required=[presentation: info:14] [distribution: test])
2438+
memo (optimized, ~29KB, required=[presentation: info:14] [distribution: test])
24392439
├── G1: (explain G2 [presentation: b:1,c:2,f:7] [distribution: test])
24402440
│ └── [presentation: info:14] [distribution: test]
24412441
│ ├── best: (explain G2="[presentation: b:1,c:2,f:7] [distribution: test]" [presentation: b:1,c:2,f:7] [distribution: test])

Diff for: pkg/sql/opt/memo/memo.go

+3
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ type Memo struct {
201201
unsafeAllowTriggersModifyingCascades bool
202202
legacyVarcharTyping bool
203203
preferBoundedCardinality bool
204+
minRowCount float64
204205
internal bool
205206

206207
// txnIsoLevel is the isolation level under which the plan was created. This
@@ -295,6 +296,7 @@ func (m *Memo) Init(ctx context.Context, evalCtx *eval.Context) {
295296
unsafeAllowTriggersModifyingCascades: evalCtx.SessionData().UnsafeAllowTriggersModifyingCascades,
296297
legacyVarcharTyping: evalCtx.SessionData().LegacyVarcharTyping,
297298
preferBoundedCardinality: evalCtx.SessionData().OptimizerPreferBoundedCardinality,
299+
minRowCount: evalCtx.SessionData().OptimizerMinRowCount,
298300
internal: evalCtx.SessionData().Internal,
299301
txnIsoLevel: evalCtx.TxnIsoLevel,
300302
}
@@ -466,6 +468,7 @@ func (m *Memo) IsStale(
466468
m.unsafeAllowTriggersModifyingCascades != evalCtx.SessionData().UnsafeAllowTriggersModifyingCascades ||
467469
m.legacyVarcharTyping != evalCtx.SessionData().LegacyVarcharTyping ||
468470
m.preferBoundedCardinality != evalCtx.SessionData().OptimizerPreferBoundedCardinality ||
471+
m.minRowCount != evalCtx.SessionData().OptimizerMinRowCount ||
469472
m.internal != evalCtx.SessionData().Internal ||
470473
m.txnIsoLevel != evalCtx.TxnIsoLevel {
471474
return true, nil

Diff for: pkg/sql/opt/memo/memo_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ func TestMemoIsStale(t *testing.T) {
543543
evalCtx.SessionData().OptimizerPreferBoundedCardinality = false
544544
notStale()
545545

546+
evalCtx.SessionData().OptimizerMinRowCount = 1.0
547+
stale()
548+
evalCtx.SessionData().OptimizerMinRowCount = 0
549+
notStale()
550+
546551
evalCtx.SessionData().Internal = true
547552
stale()
548553
evalCtx.SessionData().Internal = false

Diff for: pkg/sql/opt/memo/statistics_builder.go

+32-30
Original file line numberDiff line numberDiff line change
@@ -228,18 +228,20 @@ const (
228228
//
229229
// See props/statistics.go for more details.
230230
type statisticsBuilder struct {
231-
ctx context.Context
232-
evalCtx *eval.Context
233-
md *opt.Metadata
231+
ctx context.Context
232+
evalCtx *eval.Context
233+
md *opt.Metadata
234+
minRowCount float64
234235
}
235236

236237
func (sb *statisticsBuilder) init(ctx context.Context, evalCtx *eval.Context, md *opt.Metadata) {
237238
// This initialization pattern ensures that fields are not unwittingly
238239
// reused. Field reuse must be explicit.
239240
*sb = statisticsBuilder{
240-
ctx: ctx,
241-
evalCtx: evalCtx,
242-
md: md,
241+
ctx: ctx,
242+
evalCtx: evalCtx,
243+
md: md,
244+
minRowCount: evalCtx.SessionData().OptimizerMinRowCount,
243245
}
244246
}
245247

@@ -836,7 +838,7 @@ func (sb *statisticsBuilder) colAvgSize(tabID opt.TableID, col opt.ColumnID) uin
836838

837839
func (sb *statisticsBuilder) buildScan(scan *ScanExpr, relProps *props.Relational) {
838840
s := relProps.Statistics()
839-
if zeroCardinality := s.Init(relProps); zeroCardinality {
841+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
840842
// Short cut if cardinality is 0.
841843
return
842844
}
@@ -1085,7 +1087,7 @@ func (sb *statisticsBuilder) colStatScan(colSet opt.ColSet, scan *ScanExpr) *pro
10851087

10861088
func (sb *statisticsBuilder) buildSelect(sel *SelectExpr, relProps *props.Relational) {
10871089
s := relProps.Statistics()
1088-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1090+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
10891091
// Short cut if cardinality is 0.
10901092
return
10911093
}
@@ -1126,7 +1128,7 @@ func (sb *statisticsBuilder) colStatSelect(
11261128

11271129
func (sb *statisticsBuilder) buildProject(prj *ProjectExpr, relProps *props.Relational) {
11281130
s := relProps.Statistics()
1129-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1131+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
11301132
// Short cut if cardinality is 0.
11311133
return
11321134
}
@@ -1228,7 +1230,7 @@ func (sb *statisticsBuilder) buildInvertedFilter(
12281230
invFilter *InvertedFilterExpr, relProps *props.Relational,
12291231
) {
12301232
s := relProps.Statistics()
1231-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1233+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
12321234
// Short cut if cardinality is 0.
12331235
return
12341236
}
@@ -1289,7 +1291,7 @@ func (sb *statisticsBuilder) buildJoin(
12891291
}
12901292

12911293
s := relProps.Statistics()
1292-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1294+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
12931295
// Short cut if cardinality is 0.
12941296
return
12951297
}
@@ -1820,7 +1822,7 @@ func (sb *statisticsBuilder) colStatFromJoinRight(
18201822

18211823
func (sb *statisticsBuilder) buildIndexJoin(indexJoin *IndexJoinExpr, relProps *props.Relational) {
18221824
s := relProps.Statistics()
1823-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1825+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
18241826
// Short cut if cardinality is 0.
18251827
return
18261828
}
@@ -1901,7 +1903,7 @@ func (sb *statisticsBuilder) buildZigzagJoin(
19011903
zigzag *ZigzagJoinExpr, relProps *props.Relational, h *joinPropsHelper,
19021904
) {
19031905
s := relProps.Statistics()
1904-
if zeroCardinality := s.Init(relProps); zeroCardinality {
1906+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
19051907
// Short cut if cardinality is 0.
19061908
return
19071909
}
@@ -2002,7 +2004,7 @@ func (sb *statisticsBuilder) buildZigzagJoin(
20022004

20032005
func (sb *statisticsBuilder) buildGroupBy(groupNode RelExpr, relProps *props.Relational) {
20042006
s := relProps.Statistics()
2005-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2007+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
20062008
// Short cut if cardinality is 0.
20072009
return
20082010
}
@@ -2114,7 +2116,7 @@ func (sb *statisticsBuilder) colStatGroupBy(
21142116

21152117
func (sb *statisticsBuilder) buildSetNode(setNode RelExpr, relProps *props.Relational) {
21162118
s := relProps.Statistics()
2117-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2119+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
21182120
// Short cut if cardinality is 0.
21192121
return
21202122
}
@@ -2219,7 +2221,7 @@ func (sb *statisticsBuilder) colStatSetNodeImpl(
22192221
// buildValues builds the statistics for a VALUES expression.
22202222
func (sb *statisticsBuilder) buildValues(values ValuesContainer, relProps *props.Relational) {
22212223
s := relProps.Statistics()
2222-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2224+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
22232225
// Short cut if cardinality is 0.
22242226
return
22252227
}
@@ -2324,7 +2326,7 @@ func (sb *statisticsBuilder) colStatLiteralValues(
23242326

23252327
func (sb *statisticsBuilder) buildLimit(limit *LimitExpr, relProps *props.Relational) {
23262328
s := relProps.Statistics()
2327-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2329+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
23282330
// Short cut if cardinality is 0.
23292331
return
23302332
}
@@ -2367,7 +2369,7 @@ func (sb *statisticsBuilder) colStatLimit(
23672369

23682370
func (sb *statisticsBuilder) buildTopK(topK *TopKExpr, relProps *props.Relational) {
23692371
s := relProps.Statistics()
2370-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2372+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
23712373
// Short cut if cardinality is 0.
23722374
return
23732375
}
@@ -2409,7 +2411,7 @@ func (sb *statisticsBuilder) colStatTopK(colSet opt.ColSet, topK *TopKExpr) *pro
24092411

24102412
func (sb *statisticsBuilder) buildOffset(offset *OffsetExpr, relProps *props.Relational) {
24112413
s := relProps.Statistics()
2412-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2414+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
24132415
// Short cut if cardinality is 0.
24142416
return
24152417
}
@@ -2462,7 +2464,7 @@ func (sb *statisticsBuilder) colStatOffset(
24622464

24632465
func (sb *statisticsBuilder) buildMax1Row(max1Row *Max1RowExpr, relProps *props.Relational) {
24642466
s := relProps.Statistics()
2465-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2467+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
24662468
// Short cut if cardinality is 0.
24672469
return
24682470
}
@@ -2492,7 +2494,7 @@ func (sb *statisticsBuilder) colStatMax1Row(
24922494

24932495
func (sb *statisticsBuilder) buildOrdinality(ord *OrdinalityExpr, relProps *props.Relational) {
24942496
s := relProps.Statistics()
2495-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2497+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
24962498
// Short cut if cardinality is 0.
24972499
return
24982500
}
@@ -2537,7 +2539,7 @@ func (sb *statisticsBuilder) colStatOrdinality(
25372539

25382540
func (sb *statisticsBuilder) buildWindow(window *WindowExpr, relProps *props.Relational) {
25392541
s := relProps.Statistics()
2540-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2542+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
25412543
// Short cut if cardinality is 0.
25422544
return
25432545
}
@@ -2605,7 +2607,7 @@ func (sb *statisticsBuilder) buildProjectSet(
26052607
projectSet *ProjectSetExpr, relProps *props.Relational,
26062608
) {
26072609
s := relProps.Statistics()
2608-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2610+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
26092611
// Short cut if cardinality is 0.
26102612
return
26112613
}
@@ -2738,7 +2740,7 @@ func (sb *statisticsBuilder) buildWithScan(
27382740
withScan *WithScanExpr, relProps, bindingProps *props.Relational,
27392741
) {
27402742
s := relProps.Statistics()
2741-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2743+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
27422744
// Short cut if cardinality is 0.
27432745
return
27442746
}
@@ -2780,7 +2782,7 @@ func (sb *statisticsBuilder) colStatWithScan(
27802782

27812783
func (sb *statisticsBuilder) buildMutation(mutation RelExpr, relProps *props.Relational) {
27822784
s := relProps.Statistics()
2783-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2785+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
27842786
// Short cut if cardinality is 0.
27852787
return
27862788
}
@@ -2818,7 +2820,7 @@ func (sb *statisticsBuilder) colStatMutation(
28182820

28192821
func (sb *statisticsBuilder) buildLock(lock *LockExpr, relProps *props.Relational) {
28202822
s := relProps.Statistics()
2821-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2823+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
28222824
// Short cut if cardinality is 0.
28232825
return
28242826
}
@@ -2852,7 +2854,7 @@ func (sb *statisticsBuilder) buildVectorSearch(
28522854
search *VectorSearchExpr, relProps *props.Relational,
28532855
) {
28542856
s := relProps.Statistics()
2855-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2857+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
28562858
// Short cut if cardinality is 0.
28572859
return
28582860
}
@@ -2909,7 +2911,7 @@ func (sb *statisticsBuilder) buildVectorPartitionSearch(
29092911
search *VectorPartitionSearchExpr, relProps *props.Relational,
29102912
) {
29112913
s := relProps.Statistics()
2912-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2914+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
29132915
// Short cut if cardinality is 0.
29142916
return
29152917
}
@@ -2944,7 +2946,7 @@ func (sb *statisticsBuilder) colStatVectorPartitionSearch(
29442946

29452947
func (sb *statisticsBuilder) buildBarrier(barrier *BarrierExpr, relProps *props.Relational) {
29462948
s := relProps.Statistics()
2947-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2949+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
29482950
// Short cut if cardinality is 0.
29492951
return
29502952
}
@@ -2978,7 +2980,7 @@ func (sb *statisticsBuilder) colStatBarrier(
29782980

29792981
func (sb *statisticsBuilder) buildCall(call *CallExpr, relProps *props.Relational) {
29802982
s := relProps.Statistics()
2981-
if zeroCardinality := s.Init(relProps); zeroCardinality {
2983+
if zeroCardinality := s.Init(relProps, sb.minRowCount); zeroCardinality {
29822984
// Short-cut if cardinality is 0.
29832985
return
29842986
}

Diff for: pkg/sql/opt/memo/statistics_builder_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ func TestGetStatsFromConstraint(t *testing.T) {
112112
relProps := &props.Relational{Cardinality: props.AnyCardinality}
113113
relProps.NotNullCols = cs.ExtractNotNullCols(ctx, &evalCtx)
114114
s := relProps.Statistics()
115-
s.Init(relProps)
115+
const minRowCount = 0
116+
s.Init(relProps, minRowCount)
116117

117118
// Calculate distinct counts.
118119
sb.applyConstraintSet(cs, true /* tight */, sel, relProps, relProps.Statistics())

0 commit comments

Comments
 (0)