Skip to content

Commit 33ebee8

Browse files
craig[bot]michae2msbutler
committed
157083: opt: explore splitting disjunction over same column r=mgartner a=michae2 The SplitDisjunction rules did not consider disjunctions over expressions referencing the same column interesting, because normally these disjunctions can become multiple spans in the same constrained scan. There is one special case, however, where disjunctions over the same column might be interesting: if the table has multiple partial indexes with different predicates referencing that column. In that case we might be able to use a different partial index for each side of the disjunction. Fixes: #157073 Release note (performance improvement): This commit teaches the optimizer to split disjunctions on the same column into unions when there are multiple partial indexes with different predicates referencing that column. 157859: roachtest: skip latency verification for 2 mins after getting to steady state r=jeffswenson a=msbutler This patch modifies the latency verifier to sleep for 2 minutes after detecting steady state (i.e. catchup scan/ initial scan completion), so a test doesn't flake after a temporary post catchup scan latency blip. Informs #156707 Release note: none Co-authored-by: Michael Erickson <michae2@cockroachlabs.com> Co-authored-by: Michael Butler <butler@cockroachlabs.com>
3 parents 21eed7b + 039901a + 0beff06 commit 33ebee8

File tree

4 files changed

+431
-5
lines changed

4 files changed

+431
-5
lines changed

pkg/cmd/roachtest/tests/cluster_to_cluster.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,7 @@ func (rd *replicationDriver) main(ctx context.Context) {
12051205
if err := lv.pollLatencyUntilJobSucceeds(ctx, rd.setup.dst.db, ingestionJobID, time.Second, workloadDoneCh); err != nil {
12061206
// The latency poller may have failed because latency got too high. Grab a
12071207
// debug zip before the replication jobs spin down.
1208+
rd.t.L().Printf("latency monitor detected an error: %s", err)
12081209
rd.fetchDebugZip(ctx, rd.setup.src.nodes, "latency_source_debug.zip")
12091210
rd.fetchDebugZip(ctx, rd.setup.dst.nodes, "latency_dest_debug.zip")
12101211
return err

pkg/cmd/roachtest/tests/latency_verifier.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,11 @@ func (lv *latencyVerifier) noteHighwater(highwaterTime time.Time) {
115115
}
116116
return
117117
}
118-
118+
justSwitchedToSteadyState := false
119119
if lv.targetSteadyLatency == 0 || latency < lv.targetSteadyLatency {
120+
if !lv.latencyBecameSteady {
121+
justSwitchedToSteadyState = true
122+
}
120123
lv.latencyBecameSteady = true
121124
}
122125
if !lv.latencyBecameSteady {
@@ -147,6 +150,10 @@ func (lv *latencyVerifier) noteHighwater(highwaterTime time.Time) {
147150
lv.name, latency.Truncate(time.Millisecond), lv.maxSeenSteadyLatency.Truncate(time.Millisecond), highwaterTime)
148151
lv.setTestStatus(update)
149152
}
153+
if justSwitchedToSteadyState {
154+
lv.logger.Printf("just reached steady state, sleeping for 2 minutes to ensure no temporary latency regressions")
155+
time.Sleep(2 * time.Minute)
156+
}
150157
}
151158

152159
// pollLatencyUntilJobSucceeds polls the changefeed latency until it is

pkg/sql/opt/xform/select_funcs.go

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,7 +1941,7 @@ func (c *CustomFuncs) SplitDisjunction(
19411941
// An "interesting" pair of expressions is one where:
19421942
//
19431943
// 1. The column sets of both expressions in the pair are not
1944-
// equal.
1944+
// equal, and
19451945
// 2. Two index scans can potentially be constrained by both expressions in
19461946
// the pair.
19471947
//
@@ -1960,6 +1960,13 @@ func (c *CustomFuncs) SplitDisjunction(
19601960
// There is no possible "interesting" pair here because the left and right sides
19611961
// of the disjunction share the same columns.
19621962
//
1963+
// There is one exceptional case when a pair could be interesting even with
1964+
// equal column sets for both expressions: when the table itself contains
1965+
// multiple partial indexes with different predicates referencing the same
1966+
// column. In this case we might be able to use different partial indexes for
1967+
// both expressions, and so consider a pair interesting even with equal column
1968+
// sets.
1969+
//
19631970
// findInterestingDisjunctionPair groups all sub-expressions adjacent to the
19641971
// input's top-level OrExpr into left and right expression groups. These two
19651972
// groups form the new filter expressions on the left and right side of the
@@ -1997,11 +2004,14 @@ func (c *CustomFuncs) findInterestingDisjunctionPair(
19972004
// not match) on.
19982005
if leftColSet.Empty() {
19992006
leftColSet = cols
2007+
leftExprs = append(leftExprs, expr)
2008+
return
20002009
}
20012010

2002-
// If the current expression ColSet matches leftColSet, add the expr to
2003-
// the left group. Otherwise, add it to the right group.
2004-
if leftColSet.Equals(cols) {
2011+
// If the current expression ColSet matches leftColSet (and we're not using
2012+
// the exception for multiple referencing partial index predicates) add the
2013+
// expr to the left group. Otherwise, add it to the right group.
2014+
if leftColSet.Equals(cols) && !c.multiplePartialIndexesReferencing(sp, leftColSet) {
20052015
leftExprs = append(leftExprs, expr)
20062016
} else {
20072017
rightColSet.UnionWith(cols)
@@ -2095,6 +2105,56 @@ func (c *CustomFuncs) canMaybeConstrainIndexWithCols(
20952105
return false
20962106
}
20972107

2108+
// multiplePartialIndexesReferencing returns true if at least one of the columns
2109+
// is referenced by the predicates of multiple partial indexes. For example,
2110+
// given this table:
2111+
//
2112+
// CREATE TABLE abc (
2113+
// a INT NOT NULL,
2114+
// b INT NOT NULL,
2115+
// c INT NOT NULL,
2116+
// INDEX (a) WHERE b > 10,
2117+
// INDEX (a) WHERE b != 100 AND c < 1000,
2118+
// INDEX (c) WHERE a > 5 AND a % 2 = 0
2119+
// )
2120+
//
2121+
// Then multiplePartialIndexesReferencing will return true if called with (b) or
2122+
// (a, b) or (b, c) or (a, b, c) but will return false if called with (a) or (c)
2123+
// or (a, c).
2124+
func (c *CustomFuncs) multiplePartialIndexesReferencing(
2125+
scanPrivate *memo.ScanPrivate, cols opt.ColSet,
2126+
) bool {
2127+
md := c.e.mem.Metadata()
2128+
tabMeta := md.TableMeta(scanPrivate.Table)
2129+
2130+
var prevPartialIndexPredCols opt.ColSet
2131+
2132+
// Iterate through all partial indexes of the table and return true if one of
2133+
// the columns is referenced again after being referenced by a previous
2134+
// partial index.
2135+
for i := 0; i < tabMeta.Table.IndexCount(); i++ {
2136+
index := tabMeta.Table.Index(i)
2137+
if _, isPartialIndex := index.Predicate(); isPartialIndex {
2138+
p, ok := tabMeta.PartialIndexPredicate(i)
2139+
if !ok {
2140+
// A partial index predicate expression was not built for the
2141+
// partial index. See Builder.buildScan for details on when this
2142+
// can occur.
2143+
continue
2144+
}
2145+
pred := *p.(*memo.FiltersExpr)
2146+
partialIndexPredCols := pred.OuterCols().Intersection(cols)
2147+
// If one of the columns has now been referenced a second time, return
2148+
// true.
2149+
if partialIndexPredCols.Intersects(prevPartialIndexPredCols) {
2150+
return true
2151+
}
2152+
prevPartialIndexPredCols.UnionWith(partialIndexPredCols)
2153+
}
2154+
}
2155+
return false
2156+
}
2157+
20982158
// MakeSetPrivate constructs a new SetPrivate with given left, right, and out
20992159
// columns.
21002160
func (c *CustomFuncs) MakeSetPrivate(left, right, out opt.ColSet) *memo.SetPrivate {

0 commit comments

Comments
 (0)