@@ -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.
21002160func (c * CustomFuncs ) MakeSetPrivate (left , right , out opt.ColSet ) * memo.SetPrivate {
0 commit comments