diff --git a/pkg/sql/opt/invertedexpr/expression.go b/pkg/sql/opt/invertedexpr/expression.go index faa63e3a0f37..c81d813da4b3 100644 --- a/pkg/sql/opt/invertedexpr/expression.go +++ b/pkg/sql/opt/invertedexpr/expression.go @@ -617,11 +617,16 @@ func opSpanExpressionAndDefault( // Intersects two SpanExpressions. func intersectSpanExpressions(left, right *SpanExpression) *SpanExpression { - // Since we simply union into SpansToRead, we can end up with - // FactoredUnionSpans as a subset of SpanToRead *and* both children pruned. - // TODO(sumeer): tighten the SpansToRead for this case. expr := &SpanExpression{ - Tight: left.Tight && right.Tight, + Tight: left.Tight && right.Tight, + + // We calculate SpansToRead as the union of the left and right sides as a + // first approximation, but this may result in too many spans if either of + // the children are pruned below. SpansToRead will be recomputed in + // tryPruneChildren if needed. (It is important that SpansToRead be exactly + // what would be computed if a caller traversed the tree and explicitly + // unioned all the FactoredUnionSpans, and no looser, since the execution + // code path relies on this property.) SpansToRead: unionSpans(left.SpansToRead, right.SpansToRead), FactoredUnionSpans: intersectSpans(left.FactoredUnionSpans, right.FactoredUnionSpans), Operator: SetIntersection, @@ -675,6 +680,19 @@ func tryPruneChildren(expr *SpanExpression, op SetOperator) { expr.Operator = child.Operator expr.Left = child.Left expr.Right = child.Right + + // If child.FactoredUnionSpans is non-empty, we need to recalculate + // SpansToRead since it may have contained some spans that were removed by + // discarding child.FactoredUnionSpans. + if child.FactoredUnionSpans != nil { + expr.SpansToRead = expr.FactoredUnionSpans + if expr.Left != nil { + expr.SpansToRead = unionSpans(expr.SpansToRead, expr.Left.(*SpanExpression).SpansToRead) + } + if expr.Right != nil { + expr.SpansToRead = unionSpans(expr.SpansToRead, expr.Right.(*SpanExpression).SpansToRead) + } + } } promoteLeft := expr.Left != nil && expr.Right == nil promoteRight := expr.Left == nil && expr.Right != nil diff --git a/pkg/sql/opt/invertedexpr/testdata/expression b/pkg/sql/opt/invertedexpr/testdata/expression index 03ed544485e8..948f94a8d3dd 100644 --- a/pkg/sql/opt/invertedexpr/testdata/expression +++ b/pkg/sql/opt/invertedexpr/testdata/expression @@ -242,7 +242,7 @@ and result=_ left=b right=ac ---- span expression ├── tight: true - ├── to read: ["a", "c") + ├── to read: ["b", "b"] └── union spans: ["b", "b"] new-span-leaf name=bj tight=true span=b,j @@ -265,7 +265,7 @@ and result=_ left=b right=bj ---- span expression ├── tight: true - ├── to read: ["b", "j") + ├── to read: ["b", "b"] └── union spans: ["b", "b"] # [b, j) or [a, c) = [a, j) diff --git a/pkg/sql/opt/xform/testdata/rules/select b/pkg/sql/opt/xform/testdata/rules/select index 30cd50adbd8a..fe29333609f0 100644 --- a/pkg/sql/opt/xform/testdata/rules/select +++ b/pkg/sql/opt/xform/testdata/rules/select @@ -2009,7 +2009,8 @@ project │ ├── inverted constraint: /7/1 │ │ └── spans │ │ ├── ["B\xfdL\x00\x00\x00\x00\x00\x00\x00", "B\xfdL\x00\x00\x00\x00\x00\x00\x00"] - │ │ └── ["B\xfdN\x00\x00\x00\x00\x00\x00\x01", "B\xfdP\x00\x00\x00\x00\x00\x00\x01") + │ │ ├── ["B\xfdO\x00\x00\x00\x00\x00\x00\x00", "B\xfdO\x00\x00\x00\x00\x00\x00\x00"] + │ │ └── ["B\xfdP\x00\x00\x00\x00\x00\x00\x00", "B\xfdP\x00\x00\x00\x00\x00\x00\x00"] │ ├── key: (1) │ └── fd: (1)-->(7) └── filters