Skip to content

Commit b9754ea

Browse files
committed
opt: use optimizer_span_limit in CanMaybeGenerateLocalityOptimizedScan
Use the optimizer_span_limit session setting to further limit the maximum number of spans allowed in CanMaybeGenerateLocalityOptimizedScan. When set, the span limit replaces the default 10000 span cap if it is lower, preventing locality-optimized scans from being generated for queries that produce too many constraint spans. Release note: None
1 parent 9f3fd47 commit b9754ea

2 files changed

Lines changed: 110 additions & 1 deletion

File tree

pkg/sql/opt/xform/scan_funcs.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/cockroachdb/cockroach/pkg/sql/rowinfra"
1717
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
1818
"github.com/cockroachdb/cockroach/pkg/util/intsets"
19+
"github.com/cockroachdb/cockroach/pkg/util/log"
1920
"github.com/cockroachdb/errors"
2021
)
2122

@@ -136,7 +137,15 @@ func (c *CustomFuncs) CanMaybeGenerateLocalityOptimizedScan(scanPrivate *memo.Sc
136137

137138
// Don't apply the rule if there are too many spans, since the rule code is
138139
// O(# spans * # prefixes * # datums per prefix).
139-
if scanPrivate.Constraint.Spans.Count() > 10000 {
140+
maxSpans := 10000
141+
if spanLimit := int(c.e.evalCtx.SessionData().OptimizerSpanLimit); spanLimit > 0 && spanLimit < maxSpans {
142+
maxSpans = spanLimit
143+
}
144+
if scanPrivate.Constraint.Spans.Count() > maxSpans {
145+
log.VEventf(c.e.ctx, 2,
146+
"optimizer_span_limit: locality-optimized scan has %d spans, exceeds limit of %d",
147+
scanPrivate.Constraint.Spans.Count(), maxSpans,
148+
)
140149
return false
141150
}
142151
}
@@ -417,6 +426,7 @@ func (c *CustomFuncs) getLocalAndRemoteFilters(
417426
// in the local (left) branch of the union all should be
418427
// [/'east' - /'east'/3] [/'east'/5 - /'east']. Adding in the following check
419428
// constraint achieves this: CHECK (r IN ('east', 'west', 'central'))
429+
// TODO(michae2): Pass optimizer_span_limit to MakeCombinedFiltersConstraint.
420430
func (c *CustomFuncs) buildAllPartitionsConstraint(
421431
tabMeta *opt.TableMeta, index cat.Index, ps partition.PrefixSorter, sp *memo.ScanPrivate,
422432
) (*constraint.Constraint, bool) {

pkg/sql/opt/xform/testdata/rules/scan

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,3 +1318,102 @@ locality-optimized-search
13181318
├── limit: 3
13191319
├── flags: force-index=def_part_pkey
13201320
└── key: (14)
1321+
1322+
# --------------------------------------------------
1323+
# optimizer_span_limit with GenerateLocalityOptimizedScan
1324+
# --------------------------------------------------
1325+
1326+
# b = 1 produces 3 spans (one per partition). By default, the locality-optimized
1327+
# scan fires.
1328+
opt locality=(region=east) expect=GenerateLocalityOptimizedScan
1329+
SELECT a FROM abc_part WHERE b = 1
1330+
----
1331+
project
1332+
├── columns: a:3!null
1333+
├── cardinality: [0 - 1]
1334+
├── key: ()
1335+
├── fd: ()-->(3)
1336+
├── distribution: east
1337+
└── locality-optimized-search
1338+
├── columns: a:3!null b:4!null
1339+
├── left columns: a:11 b:12
1340+
├── right columns: a:19 b:20
1341+
├── cardinality: [0 - 1]
1342+
├── key: ()
1343+
├── fd: ()-->(3,4)
1344+
├── distribution: east
1345+
├── scan abc_part@b_idx
1346+
│ ├── columns: a:11!null b:12!null
1347+
│ ├── constraint: /9/12: [/'east'/1 - /'east'/1]
1348+
│ ├── cardinality: [0 - 1]
1349+
│ ├── key: ()
1350+
│ └── fd: ()-->(11,12)
1351+
└── scan abc_part@b_idx
1352+
├── columns: a:19!null b:20!null
1353+
├── constraint: /17/20
1354+
│ ├── [/'central'/1 - /'central'/1]
1355+
│ └── [/'west'/1 - /'west'/1]
1356+
├── cardinality: [0 - 1]
1357+
├── key: ()
1358+
└── fd: ()-->(19,20)
1359+
1360+
# With optimizer_span_limit=3, the 3 spans are within the limit.
1361+
opt locality=(region=east) expect=GenerateLocalityOptimizedScan set=(optimizer_span_limit=3)
1362+
SELECT a FROM abc_part WHERE b = 1
1363+
----
1364+
project
1365+
├── columns: a:3!null
1366+
├── cardinality: [0 - 1]
1367+
├── key: ()
1368+
├── fd: ()-->(3)
1369+
├── distribution: east
1370+
└── locality-optimized-search
1371+
├── columns: a:3!null b:4!null
1372+
├── left columns: a:11 b:12
1373+
├── right columns: a:19 b:20
1374+
├── cardinality: [0 - 1]
1375+
├── key: ()
1376+
├── fd: ()-->(3,4)
1377+
├── distribution: east
1378+
├── scan abc_part@b_idx
1379+
│ ├── columns: a:11!null b:12!null
1380+
│ ├── constraint: /9/12: [/'east'/1 - /'east'/1]
1381+
│ ├── cardinality: [0 - 1]
1382+
│ ├── key: ()
1383+
│ └── fd: ()-->(11,12)
1384+
└── scan abc_part@b_idx
1385+
├── columns: a:19!null b:20!null
1386+
├── constraint: /17/20
1387+
│ ├── [/'central'/1 - /'central'/1]
1388+
│ └── [/'west'/1 - /'west'/1]
1389+
├── cardinality: [0 - 1]
1390+
├── key: ()
1391+
└── fd: ()-->(19,20)
1392+
1393+
# With optimizer_span_limit=2, the 3 spans exceed the limit, so the locality-
1394+
# optimized scan does not fire.
1395+
opt locality=(region=east) expect-not=GenerateLocalityOptimizedScan set=(optimizer_span_limit=2)
1396+
SELECT a FROM abc_part WHERE b = 1
1397+
----
1398+
project
1399+
├── columns: a:3!null
1400+
├── cardinality: [0 - 1]
1401+
├── key: ()
1402+
├── fd: ()-->(3)
1403+
├── distribution: east
1404+
└── select
1405+
├── columns: a:3!null b:4!null
1406+
├── cardinality: [0 - 1]
1407+
├── key: ()
1408+
├── fd: ()-->(3,4)
1409+
├── distribution: east
1410+
├── scan abc_part
1411+
│ ├── columns: a:3!null b:4
1412+
│ ├── check constraint expressions
1413+
│ │ ├── r:1 IN ('central', 'east', 'west') [outer=(1), constraints=(/1: [/'central' - /'central'] [/'east' - /'east'] [/'west' - /'west']; tight)]
1414+
│ │ └── t:2 IN (1, 2, 3) [outer=(2), constraints=(/2: [/1 - /1] [/2 - /2] [/3 - /3]; tight)]
1415+
│ ├── key: (3)
1416+
│ ├── fd: (3)-->(4), (4)~~>(3)
1417+
│ └── distribution: east
1418+
└── filters
1419+
└── b:4 = 1 [outer=(4), constraints=(/4: [/1 - /1]; tight), fd=()-->(4)]

0 commit comments

Comments
 (0)