Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opt: improve FDs for Intersect and Except variants #66444

Merged
merged 1 commit into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions pkg/sql/opt/colset.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,18 @@ func (s ColSet) ToList() ColList {
// TranslateColSet(ColSet{5, 6}, Right, Out) -> ColSet{8, 9}
// TranslateColSet(ColSet{9}, Out, Right) -> ColSet{6}
//
// Note that for the output of TranslateColSet to be correct, colSetIn must be
// a subset of the columns in `from`. TranslateColSet does not check that this
// is the case, because that would require building a ColSet from `from`, and
// checking that colSetIn.SubsetOf(fromColSet) is true -- a lot of computation
// for a validation check. It is not correct or sufficient to check that
// colSetIn.Len() == colSetOut.Len(), because it is possible that colSetIn and
// colSetOut could have different lengths and still be valid. Consider the
// following case:
// Any columns in the input set that do not appear in the from list are ignored.
//
// Even when all the columns in the input set appear in the from list, it is
// possible for the input and output sets to have different cardinality.
// Consider the following case:
//
// SELECT x, x, y FROM xyz UNION SELECT a, b, c FROM abc
//
// TranslateColSet(ColSet{x, y}, Left, Right) correctly returns
// ColSet{a, b, c}, even though ColSet{x, y}.Len() != ColSet{a, b, c}.Len().
// TranslateColSet(ColSet{x, y}, {x, x, y}, {a, b, c}) returns ColSet{a, b, c}.
//
// Conversely, TranslateColSet(ColSet{a, b, c}, {a, b, c}, {x, x, y}) returns
// ColSet{x, y}.
func TranslateColSet(colSetIn ColSet, from ColList, to ColList) ColSet {
var colSetOut ColSet
for i := range from {
Expand All @@ -147,3 +146,12 @@ func TranslateColSet(colSetIn ColSet, from ColList, to ColList) ColSet {

return colSetOut
}

// TranslateColSetStrict is a version of TranslateColSet which requires that all
// columns in the input set appear in the from list.
func TranslateColSetStrict(colSetIn ColSet, from ColList, to ColList) ColSet {
if util.CrdbTestBuild && !colSetIn.SubsetOf(from.ToSet()) {
panic(errors.AssertionFailedf("input set contains unknown columns"))
}
return TranslateColSet(colSetIn, from, to)
}
5 changes: 5 additions & 0 deletions pkg/sql/opt/exec/execbuilder/testdata/fk
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ vectorized: true
│ │
│ └── • hash join
│ │ equality: (p) = (p)
│ │ left cols are key
│ │ right cols are key
│ │
│ ├── • except all
Expand All @@ -512,6 +513,7 @@ vectorized: true
└── • hash join
│ equality: (p) = (p)
│ left cols are key
│ right cols are key
├── • except all
Expand Down Expand Up @@ -618,6 +620,7 @@ vectorized: true
└── • hash join
│ equality: (c) = (c)
│ left cols are key
│ right cols are key
├── • except all
Expand Down Expand Up @@ -758,6 +761,7 @@ vectorized: true
└── • hash join
│ equality: (c) = (c)
│ left cols are key
│ right cols are key
├── • except all
Expand Down Expand Up @@ -890,6 +894,7 @@ vectorized: true
└── • hash join
│ equality: (x) = (y)
│ left cols are key
│ right cols are key
├── • except all
Expand Down
12 changes: 6 additions & 6 deletions pkg/sql/opt/exec/execbuilder/testdata/union
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ vectorized: true
·
• intersect
│ columns: (b, c, d, e)
│ ordering: +b,+c,+d,+e
│ ordering: +b,+d,+c,+e
│ estimated row count: 1 (missing stats)
├── • filter
Expand Down Expand Up @@ -624,7 +624,7 @@ vectorized: true
table: abcde@abcde_b_c_d_e_idx
spans: FULL SCAN
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy0lF-L2kAUxd_7KS73KcEpbv7olgFhdmuWBlyzTUL_UERi5tYG0iSdjLBF_O4lSdtVu6Z12b4Ic2Z-95x7kGyx_pYjR-_D3ezKn4Mx9aM4ejtj8M4Lr4PIMyHyZt7rGFYMUgaSAcFNGNyCcUJPVqkk8OexF0bNfd8zE96_8UIPjBQmYJlwNZ-CIWECZEIQTr0Qrj_CChkWpaR58pVq5J_QwgXDSpUp1XWpGmnbPvDlPfILhllRbXQjLximpSLkW9SZzgk5xskqp5ASSWp4gQwl6STL27FtItH-LlfLdCmXtMzkPTKMqqSoObxEhsFGcxA2Ew4TLhMjXOwYlhv94FjrZE3IrR3791Q3Wa5JkRpah5E6nYMh7KYgzrk_j1_97Ek4MAHhmicj2OdE2C_G_p_FOE8qxnnOYtxzIkyzWmdFqofuYQRhsV_rNusrSYokh0Z2TjqPnuQ8egbn8UnnB8NNUXbDDvwWDfm3J4_EvyW1poh0UA3HhwvE3yvie5-Iq9kMGeb0WRvCGjBhD5hwBky4A3OisvWXP-Xff7i9Kk5tfnlO5yHVVVnUdNzAo5MvmrVJrqmrsS43KqU7VaatTXcMWq4VJNW6u7W6g190V03AfdjqhUf9sN0LO_2w0wu7_bDbC48PYOsYHp0B28fwuBe-PIq92L34EQAA___K-yzi
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy0lF-L2kAUxd_7KS73KcEpbv7olgFhdmuWBlyzTUL_UERi5tYG0iSdjLBF_O4lSdtVu6Z12b4Ic2Z-95x7kGyx_pYjR-_D3ezKn4Mx9aM4ejtj8M4Lr4PIMyHyZt7rGFYMUgaSAcFNGNyCcUJPVqkk8OexF0bNfd8zE96_8UIPjBQmYJlwNZ-CIWECZEIQTr0Qrj_CChkWpaR58pVq5J_QwgXDSpUp1XWpGmnbPvDlPfILhllRbXQjLximpSLkW9SZzgk5xskqp5ASSWp4gQwl6STL27FtItH-LlfLdCmXtMzkPTKMqqSoObxEhsFGcxA2Ew4TLhMjXOwYlhv94FjrZE3IrR3791Q3Wa5JkRpah5E6nYMh7KYgzrk_j1_97Ek4MAHhmicj2OdE2C_G_p_FOE8qxnnOYtxzIkyzWmdFqofuYQRhsV_rNusrSYokh0Z2TjqPnuQ8egbn8UnnB8NNUXbDDvwWDfm3J4_EvyW1poh0UA3HhwvE3yvie5-Iq9kMGeb0WRvCGjDhDJiwB0y4A3OisvWXP-Xff7i9Kk5tfnlO5yHVVVnUdNzAo5MvmrVJrqmrsS43KqU7VaatTXcMWq4VJNW6u7W6g190V03AfdjqhUf9sN0LO_2w0wu7_bDbC48PYOsYHp0B28fwuBe-PIq92L34EQAA___LAyzi

query T
EXPLAIN (DISTSQL,VERBOSE) SELECT b, c, d, e FROM (SELECT b, c, d, e FROM abcde EXCEPT SELECT b, c, d, e FROM abcde) WHERE c = 1 AND d = e ORDER BY b, c, d, e
Expand All @@ -634,7 +634,7 @@ vectorized: true
·
• except
│ columns: (b, c, d, e)
│ ordering: +b,+c,+d,+e
│ ordering: +b,+d,+c,+e
│ estimated row count: 1 (missing stats)
├── • filter
Expand Down Expand Up @@ -663,7 +663,7 @@ vectorized: true
table: abcde@abcde_b_c_d_e_idx
spans: FULL SCAN
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy0lN9q20wQxe-_pxjmSsL74eiPnbJg2CRWqMGxUkm0KcUYWTt1BaqkrtaQEvzuRVLT2G6k1iG9MezZ_c05czB6wOpbhhy9u9v5xWwBxnQWRuG7OYP3XnDph54JoTf3riJYM0gYSAYE14F_A0aHHq8TSeDdXXm3URfbvDHhw1sv8MBIYAKWCReLKRgSJkAm-MHUC-Dy4x6JDPNC0iL-ShXyT2jhkmGpioSqqlC19NA8mMl75GcM07zc6lpeMkwKRcgfUKc6I-QYxeuMAoolqeEZMpSk4zRrxjbRRPO7Wq-SlVzRKpX3yDAs47zi8D8y9Leag7CZcJhwmRjhcsew2Oonx0rHG0Ju7djfp7pOM02K1NA6jNTqHAxh101xzmeL6M3PwoQDExCu2RnBPiXCfjH2vyzGeVExzmsW454SYZpWOs0TPXQPIwiLPa5br68kKZIcatnpdB69yHn0Cs7jTucnw21etMMO_JY1-acnz8S_IbWhkLRfDseHC0TfS-KPH4qL-RwZZvRZG8IaMGEPmHAGTLgDc6LSzZff5V__tr0eutY-P6XwgKqyyCs6Xv_ZyWf1ziQ31HZYFVuV0K0qksamPfoN1wiSKt3eWu1hlrdXdcB92OqF3X7Y7oWdftjphUf9sNsLjw9g6xgenQDbx_C4Fz4_ir3c_fcjAAD__7UbLSI=
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJy0lN9q20wQxe-_pxjmSsL74eiPnbJg2CRWqMGxUkm0KcUYWTt1BaqkrtaQEvzuRVLT2G6k1iG9MezZ_c05czB6wOpbhhy9u9v5xWwBxnQWRuG7OYP3XnDph54JoTf3riJYM0gYSAYE14F_A0aHHq8TSeDdXXm3URfbvDHhw1sv8MBIYAKWCReLKRgSJkAm-MHUC-Dy4x6JDPNC0iL-ShXyT2jhkmGpioSqqlC19NA8mMl75GcM07zc6lpeMkwKRcgfUKc6I-QYxeuMAoolqeEZMpSk4zRrxjbRRPO7Wq-SlVzRKpX3yDAs47zi8D8y9Leag7CZcJhwmRjhcsew2Oonx0rHG0Ju7djfp7pOM02K1NA6jNTqHAxh101xzmeL6M3PwoQDExCu2RnBPiXCfjH2vyzGeVExzmsW454SYZpWOs0TPXQPIwiLPa5br68kKZIcatnpdB69yHn0Cs7jTucnw21etMMO_JY1-acnz8S_IbWhkLRfDseHC0TfS-KPH4qL-RwZZvRZG8IaMOEMmLAHTLgDc6LSzZff5V__tr0eutY-P6XwgKqyyCs6Xv_ZyWf1ziQ31HZYFVuV0K0qksamPfoN1wiSKt3eWu1hlrdXdcB92OqF3X7Y7oWdftjphUf9sNsLjw9g6xgenQDbx_C4Fz4_ir3c_fcjAAD__7UjLSI=

query T
EXPLAIN (DISTSQL,VERBOSE) SELECT * FROM (SELECT * FROM abcde EXCEPT ALL SELECT * FROM abcde) WHERE c = 1 AND d = e ORDER BY a
Expand Down Expand Up @@ -712,7 +712,7 @@ vectorized: true
·
• intersect all
│ columns: (a, b, c, d, e)
│ ordering: +b,+c,+d,+a,+e
│ ordering: +b,+d,+a,+c,+e
│ estimated row count: 1 (missing stats)
├── • filter
Expand Down Expand Up @@ -741,7 +741,7 @@ vectorized: true
table: abcde@abcde_b_c_d_e_idx
spans: FULL SCAN
·
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk9uLm1AQxt_7VwzzpM2UjZdAORA42calQjZuVXqhhGA801Swao8GtoT870Ut7BqStCn7EpjLN993fsE91j9zFOh9fljM_CUYcz-Kow8Lgo9eeBtEngmRt_DexfAa7sLgHoxhmWxSxeAvYy-M2vZssYATGyZ8eu-FHhgpTMEyYbacg6FgCmxCEM69EG6_wIYgJVAETJAgYVEqXiY_uEbxFS1cEVa6TLmuS9229t2Crx5RjAmzoto1bXtFmJaaUeyxyZqcUWCcbHIOOVGsb8ZIqLhJsrw726WT3e96s07Xas3rTD0iYVQlRS3gDa4OhOWueTpfN8mWUVgH-vcId1nesGZ9Yw39-74AQzotGSGEv4zf_gEkXZiCnJhnI9jXRHhOwX4xCs5_UXBekoJ7NsKT864otWLNamC8apV_WznxjnvWW464Caobd_iS-FfFYvg9IGHO3xpD2iOSzoikOyJpjUhORuZUZ9vvp0dIGOwaAdIiaZN0SLokJ2chTK75H0Kuq7Ko-RjGycvjlgCrLfdE63KnU37QZdrZ9GXQ6bqG4rrpp1Zf-EU_agM-F1sXxe5AbB-L7Yti57Kzc4WzdSx2L4onR86rw6vfAQAA___SNa8C
Diagram: https://cockroachdb.github.io/distsqlplan/decode.html#eJysk9uLm1AQxt_7VwzzpM2UjZdAORA42calQjZuVXqhhGA801Swao8GtoT870Ut7BqStCn7EpjLN993fsE91j9zFOh9fljM_CUYcz-Kow8Lgo9eeBtEngmRt_DexfAa7sLgHoxhmWxSxeAvYy-M2vZssYATGyZ8eu-FHhgpTMEyYbacg6FgCmxCEM69EG6_wIYgJVAETJAgYVEqXiY_uEbxFS1cEVa6TLmuS9229t2Crx5RjAmzoto1bXtFmJaaUeyxyZqcUWCcbHIOOVGsb8ZIqLhJsrw726WT3e96s07Xas3rTD0iYVQlRS3gDa4OhOWueTpfN8mWUVgH-vcId1nesGZ9Yw39-74AQzotGSGEv4zf_gEkXZiCnJhnI9jXRHhOwX4xCs5_UXBekoJ7NsKT864otWLNamC8apV_WznxjnvWW464Caobd_iS-FfFYvg9IGHO3xpD2iOS7oikNSLpjEhORuZUZ9vvp0dIGOwaAdIiaZN0SLokJ2chTK75H0Kuq7Ko-RjGycvjlgCrLfdE63KnU37QZdrZ9GXQ6bqG4rrpp1Zf-EU_agM-F1sXxe5AbB-L7Yti57Kzc4WzdSx2L4onR86rw6vfAQAA___SLa8C

# Regression test for #64181. Ensure that a projection on top of an ordered
# UNION ALL correctly projects away ordering columns.
Expand Down
43 changes: 23 additions & 20 deletions pkg/sql/opt/memo/logical_props_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ func (b *logicalPropsBuilder) buildLocalityOptimizedSearchProps(
func (b *logicalPropsBuilder) buildSetProps(setNode RelExpr, rel *props.Relational) {
BuildSharedProps(setNode, &rel.Shared)

op := setNode.Op()
leftProps := setNode.Child(0).(RelExpr).Relational()
rightProps := setNode.Child(1).(RelExpr).Relational()
setPrivate := setNode.Private().(*SetPrivate)
Expand Down Expand Up @@ -720,12 +721,7 @@ func (b *logicalPropsBuilder) buildSetProps(setNode RelExpr, rel *props.Relation

// Functional Dependencies
// -----------------------
switch setNode.Op() {
case opt.UnionOp, opt.IntersectOp, opt.ExceptOp:
// These operators eliminate duplicates, so a strict key exists.
rel.FuncDeps.AddStrictKey(rel.OutputCols, rel.OutputCols)
}
switch setNode.Op() {
switch op {
case opt.UnionOp, opt.UnionAllOp, opt.LocalityOptimizedSearchOp:
// If columns at ordinals (i, j) are equivalent in both the left input
// and right input, then the output columns at ordinals at (i, j) are
Expand All @@ -738,27 +734,34 @@ func (b *logicalPropsBuilder) buildSetProps(setNode RelExpr, rel *props.Relation
}
}
}

case opt.IntersectOp, opt.IntersectAllOp, opt.ExceptOp, opt.ExceptAllOp:
// Intersect, IntersectAll, Except and ExceptAll only output rows from
// the left input, so if columns at ordinals (i, j) are equivalent in
// the left input, then they are equivalent in the output.
// TODO(mgartner): The entire FD set on the left side can be used, but
// columns may need to be mapped. Intersections can combine FD
// information from both the left and the right.
for i := range setPrivate.OutCols {
for j := i + 1; j < len(setPrivate.OutCols); j++ {
if leftProps.FuncDeps.AreColsEquiv(setPrivate.LeftCols[i], setPrivate.LeftCols[j]) {
rel.FuncDeps.AddEquivalency(setPrivate.OutCols[i], setPrivate.OutCols[j])
}
}
// With these operators, the output is a subset of the left input, so all
// the left FDs still hold (similar to a Select).
rel.FuncDeps.RemapFrom(&leftProps.FuncDeps, setPrivate.LeftCols, setPrivate.OutCols)

if op == opt.IntersectOp || op == opt.IntersectAllOp {
// With Intersect operators, the output is also a subset of the right input,
// so all the right FDs apply as well.
var remapped props.FuncDepSet
remapped.RemapFrom(&rightProps.FuncDeps, setPrivate.RightCols, setPrivate.OutCols)
rel.FuncDeps.AddFrom(&remapped)
}
}

// Add a strict key for variants that eliminate duplicates.
switch op {
case opt.UnionOp, opt.IntersectOp, opt.ExceptOp:
rel.FuncDeps.AddStrictKey(rel.OutputCols, rel.OutputCols)
}

// Cardinality
// -----------
// Calculate cardinality of the set operator.
rel.Cardinality = b.makeSetCardinality(
setNode.Op(), leftProps.Cardinality, rightProps.Cardinality)
rel.Cardinality = b.makeSetCardinality(op, leftProps.Cardinality, rightProps.Cardinality)
if rel.FuncDeps.HasMax1Row() {
rel.Cardinality = rel.Cardinality.Limit(1)
}

// Statistics
// ----------
Expand Down
6 changes: 3 additions & 3 deletions pkg/sql/opt/memo/statistics_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1851,8 +1851,8 @@ func (sb *statisticsBuilder) colStatSetNodeImpl(
s := &relProps.Stats
setPrivate := setNode.Private().(*SetPrivate)

leftCols := opt.TranslateColSet(outputCols, setPrivate.OutCols, setPrivate.LeftCols)
rightCols := opt.TranslateColSet(outputCols, setPrivate.OutCols, setPrivate.RightCols)
leftCols := opt.TranslateColSetStrict(outputCols, setPrivate.OutCols, setPrivate.LeftCols)
rightCols := opt.TranslateColSetStrict(outputCols, setPrivate.OutCols, setPrivate.RightCols)
leftColStat := sb.colStatFromChild(leftCols, setNode, 0 /* childIdx */)
rightColStat := sb.colStatFromChild(rightCols, setNode, 1 /* childIdx */)

Expand Down Expand Up @@ -2356,7 +2356,7 @@ func (sb *statisticsBuilder) colStatWithScan(

// Calculate the corresponding col stat in the bound expression and convert
// the result.
inColSet := opt.TranslateColSet(colSet, withScan.OutCols, withScan.InCols)
inColSet := opt.TranslateColSetStrict(colSet, withScan.OutCols, withScan.InCols)
inColStat := sb.colStat(inColSet, boundExpr)

colStat, _ := s.ColStats.Add(colSet)
Expand Down
12 changes: 8 additions & 4 deletions pkg/sql/opt/memo/testdata/logprops/set
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ intersect
├── columns: x:1(int!null) y:2(int) x:1(int!null)
├── left columns: x:1(int!null) y:2(int) x:1(int!null)
├── right columns: v:6(int) u:5(int) rowid:7(int)
├── key: (1,2)
├── key: (1)
├── fd: ()-->(2)
├── interesting orderings: (+1)
├── project
│ ├── columns: x:1(int!null) y:2(int)
Expand Down Expand Up @@ -92,7 +93,8 @@ except
├── columns: x:1(int!null) x:1(int!null) y:2(int)
├── left columns: x:1(int!null) x:1(int!null) y:2(int)
├── right columns: u:5(int) v:6(int) v:6(int)
├── key: (1,2)
├── key: (1)
├── fd: (1)-->(2)
├── interesting orderings: (+1)
├── project
│ ├── columns: x:1(int!null) y:2(int)
Expand Down Expand Up @@ -489,7 +491,8 @@ intersect-all
├── columns: a:1(int!null) b:2(int) c:3(int)
├── left columns: a:1(int!null) b:2(int) c:3(int)
├── right columns: a:6(int) b:7(int) c:8(int)
├── fd: (1)==(3), (3)==(1)
├── key: (1)
├── fd: (1)==(2,3), (3)==(1,2), (2)==(1,3)
├── interesting orderings: (+1)
├── select
│ ├── columns: a:1(int!null) b:2(int) c:3(int!null)
Expand Down Expand Up @@ -541,7 +544,8 @@ except-all
├── columns: a:1(int!null) b:2(int) c:3(int)
├── left columns: a:1(int!null) b:2(int) c:3(int)
├── right columns: a:6(int) b:7(int) c:8(int)
├── fd: (1)==(3), (3)==(1)
├── key: (1)
├── fd: (1)-->(2), (1)==(3), (3)==(1)
├── interesting orderings: (+1)
├── select
│ ├── columns: a:1(int!null) b:2(int) c:3(int!null)
Expand Down
63 changes: 33 additions & 30 deletions pkg/sql/opt/memo/testdata/stats/set
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ intersect
├── left columns: a.x:1(int!null) y:2(int) a.x:1(int!null)
├── right columns: z:7(int) b.x:6(int) rowid:9(int)
├── stats: [rows=2, distinct(1,2)=2, null(1,2)=0]
├── key: (1,2)
├── key: (1)
├── fd: ()-->(2)
├── project
│ ├── columns: a.x:1(int!null) y:2(int)
│ ├── stats: [rows=5000, distinct(1,2)=5000, null(1,2)=0]
Expand Down Expand Up @@ -283,6 +284,8 @@ intersect-all
├── left columns: a.x:1(int!null) y:2(int) a.x:1(int!null)
├── right columns: z:7(int) b.x:6(int) rowid:9(int)
├── stats: [rows=2]
├── key: (1)
├── fd: ()-->(2)
├── project
│ ├── columns: a.x:1(int!null) y:2(int)
│ ├── stats: [rows=5000]
Expand Down Expand Up @@ -401,7 +404,8 @@ except
├── left columns: a.x:1(int!null) a.x:1(int!null) y:2(int)
├── right columns: b.x:6(int) z:7(int) z:7(int)
├── stats: [rows=5000, distinct(1,2)=5000, null(1,2)=0]
├── key: (1,2)
├── key: (1)
├── fd: (1)-->(2)
├── project
│ ├── columns: a.x:1(int!null) y:2(int)
│ ├── stats: [rows=5000, distinct(1,2)=5000, null(1,2)=0]
Expand Down Expand Up @@ -441,6 +445,8 @@ except-all
├── left columns: a.x:1(int!null) a.x:1(int!null) y:2(int)
├── right columns: b.x:6(int) z:7(int) z:7(int)
├── stats: [rows=5000]
├── key: (1)
├── fd: (1)-->(2)
├── project
│ ├── columns: a.x:1(int!null) y:2(int)
│ ├── stats: [rows=5000]
Expand Down Expand Up @@ -869,7 +875,7 @@ except-all
└── fd: (10)-->(7-9,11,12)

# Regression test for #35715.
opt colstat=(5,2)
opt colstat=(1,2)
SELECT * FROM
(((VALUES (NULL, true), (2, true)) EXCEPT (VALUES (1, NULL), (1, NULL)))) AS t(a, b)
WHERE a IS NULL and b
Expand All @@ -878,9 +884,10 @@ except
├── columns: a:1(int) b:2(bool!null)
├── left columns: column1:1(int) column2:2(bool!null)
├── right columns: column1:3(int) column2:4(bool)
├── cardinality: [0 - 2]
├── stats: [rows=1, distinct(1,2)=1, null(1,2)=0, distinct(2,5)=1, null(2,5)=0]
├── key: (1,2)
├── cardinality: [0 - 1]
├── stats: [rows=1, distinct(1,2)=1, null(1,2)=0]
├── key: ()
├── fd: ()-->(1,2)
├── select
│ ├── columns: column1:1(int) column2:2(bool!null)
│ ├── cardinality: [0 - 2]
Expand Down Expand Up @@ -922,7 +929,8 @@ except
├── right columns: column1:3(int) column2:4(int)
├── cardinality: [0 - 3]
├── stats: [rows=2, distinct(1,2)=2, null(1,2)=0.666666667]
├── key: (1,2)
├── key: (2)
├── fd: ()-->(1)
├── select
│ ├── columns: column1:1(int) column2:2(int)
│ ├── cardinality: [0 - 3]
Expand Down Expand Up @@ -956,29 +964,24 @@ except
opt disable=SimplifyIntersectRight
VALUES (1), (2) INTERSECT VALUES (NULL) ORDER BY 1
----
sort
intersect
├── columns: column1:1(int)
├── left columns: column1:1(int)
├── right columns: column1:2(int)
├── cardinality: [0 - 1]
├── stats: [rows=1, distinct(1)=1, null(1)=0]
├── key: (1)
├── ordering: +1
└── intersect
├── columns: column1:1(int)
├── left columns: column1:1(int)
├── right columns: column1:2(int)
├── cardinality: [0 - 1]
├── stats: [rows=1, distinct(1)=1, null(1)=0]
├── key: (1)
├── values
│ ├── columns: column1:1(int!null)
│ ├── cardinality: [2 - 2]
│ ├── stats: [rows=2, distinct(1)=2, null(1)=0]
│ ├── (1,) [type=tuple{int}]
│ └── (2,) [type=tuple{int}]
└── values
├── columns: column1:2(int)
├── cardinality: [1 - 1]
├── stats: [rows=1, distinct(2)=1, null(2)=1]
├── key: ()
├── fd: ()-->(2)
└── (NULL,) [type=tuple{int}]
├── key: ()
├── fd: ()-->(1)
├── values
│ ├── columns: column1:1(int!null)
│ ├── cardinality: [2 - 2]
│ ├── stats: [rows=2, distinct(1)=2, null(1)=0]
│ ├── (1,) [type=tuple{int}]
│ └── (2,) [type=tuple{int}]
└── values
├── columns: column1:2(int)
├── cardinality: [1 - 1]
├── stats: [rows=1, distinct(2)=1, null(2)=1]
├── key: ()
├── fd: ()-->(2)
└── (NULL,) [type=tuple{int}]
Loading