diff --git a/pkg/sql/opt/exec/execbuilder/testdata/stats b/pkg/sql/opt/exec/execbuilder/testdata/stats index fccd83cdfb81..d6e5a40c19a5 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/stats +++ b/pkg/sql/opt/exec/execbuilder/testdata/stats @@ -317,20 +317,20 @@ limit ├── cardinality: [0 - 1] ├── immutable ├── stats: [rows=1] - ├── cost: 226.06 + ├── cost: 226.059998 ├── key: () ├── fd: ()-->(1) ├── select │ ├── columns: j:1 │ ├── immutable - │ ├── stats: [rows=10, distinct(1)=1, null(1)=10] - │ ├── cost: 226.04 + │ ├── stats: [rows=10.0000001, distinct(1)=1, null(1)=10] + │ ├── cost: 226.039998 │ ├── fd: ()-->(1) │ ├── limit hint: 1.00 │ ├── scan tj │ │ ├── columns: j:1 │ │ ├── stats: [rows=1000, distinct(1)=100, null(1)=10] - │ │ ├── cost: 216.02 + │ │ ├── cost: 216.019998 │ │ ├── limit hint: 100.00 │ │ └── prune: (1) │ └── filters diff --git a/pkg/sql/opt/memo/statistics_builder.go b/pkg/sql/opt/memo/statistics_builder.go index f1824ac0ce7e..4b432e7c6b93 100644 --- a/pkg/sql/opt/memo/statistics_builder.go +++ b/pkg/sql/opt/memo/statistics_builder.go @@ -702,7 +702,7 @@ func (sb *statisticsBuilder) buildScan(scan *ScanExpr, relProps *props.Relationa // calculate selectivity = 1/9 + 1/9 + 1/9 = 1/3 in spanStatsUnion, which // is too high. Instead, we should use the value calculated from the // combined spans, which in this case is simply 1/9. - s.Selectivity = min(s.Selectivity, spanStatsUnion.Selectivity) + s.Selectivity = props.MinSelectivity(s.Selectivity, spanStatsUnion.Selectivity) s.RowCount = min(s.RowCount, spanStatsUnion.RowCount) sb.finalizeFromCardinality(relProps) @@ -827,7 +827,7 @@ func (sb *statisticsBuilder) constrainScan( s.ApplySelectivity(sb.selectivityFromNullsRemoved(scan, notNullCols, constrainedCols)) // Adjust the selectivity so we don't double-count the histogram columns. - s.ApplySelectivity(1.0 / sb.selectivityFromSingleColDistinctCounts(histCols, scan, s)) + s.UnapplySelectivity(sb.selectivityFromSingleColDistinctCounts(histCols, scan, s)) } func (sb *statisticsBuilder) colStatScan(colSet opt.ColSet, scan *ScanExpr) *props.ColumnStatistic { @@ -841,7 +841,7 @@ func (sb *statisticsBuilder) colStatScan(colSet opt.ColSet, scan *ScanExpr) *pro colStat.Histogram = inputColStat.Histogram } - if s.Selectivity != 1 { + if s.Selectivity != props.OneSelectivity { tableStats := sb.makeTableStatistics(scan.Table) colStat.ApplySelectivity(s.Selectivity, tableStats.RowCount) } @@ -885,7 +885,7 @@ func (sb *statisticsBuilder) colStatSelect( // filter conditions were pushed down into the input after s.Selectivity // was calculated. For example, an index scan or index join created during // exploration could absorb some of the filter conditions. - selectivity := s.RowCount / inputStats.RowCount + selectivity := props.MakeSelectivity(s.RowCount / inputStats.RowCount) colStat.ApplySelectivity(selectivity, inputStats.RowCount) if colSet.Intersects(relProps.NotNullCols) { colStat.NullCount = 0 @@ -1013,7 +1013,7 @@ func (sb *statisticsBuilder) buildInvertedFilter( s.ApplySelectivity(sb.selectivityFromNullsRemoved(invFilter, relProps.NotNullCols, constrainedCols)) // Adjust the selectivity so we don't double-count the histogram columns. - s.ApplySelectivity(1.0 / sb.selectivityFromSingleColDistinctCounts(histCols, invFilter, s)) + s.UnapplySelectivity(sb.selectivityFromSingleColDistinctCounts(histCols, invFilter, s)) sb.finalizeFromCardinality(relProps) } @@ -1026,7 +1026,7 @@ func (sb *statisticsBuilder) colStatInvertedFilter( inputStats := &invFilter.Input.Relational().Stats colStat := sb.copyColStatFromChild(colSet, invFilter, s) - if s.Selectivity != 1 { + if s.Selectivity != props.OneSelectivity { colStat.ApplySelectivity(s.Selectivity, inputStats.RowCount) } @@ -1067,7 +1067,7 @@ func (sb *statisticsBuilder) buildJoin( // are implicit equality conditions on KeyCols. if h.filterIsTrue { s.RowCount = leftStats.RowCount * rightStats.RowCount - s.Selectivity = 1 + s.Selectivity = props.OneSelectivity switch h.joinType { case opt.InnerJoinOp, opt.InnerJoinApplyOp: case opt.LeftJoinOp, opt.LeftJoinApplyOp: @@ -1090,14 +1090,14 @@ func (sb *statisticsBuilder) buildJoin( // Don't set the row count to 0 since we can't guarantee that the // cardinality is 0. s.RowCount = epsilon - s.Selectivity = epsilon + s.Selectivity = props.MakeSelectivity(epsilon) } return } // Shortcut if the ON condition is false or there is a contradiction. if h.filters.IsFalse() { - s.Selectivity = 0 + s.Selectivity = props.ZeroSelectivity switch h.joinType { case opt.InnerJoinOp, opt.InnerJoinApplyOp: s.RowCount = 0 @@ -1119,7 +1119,7 @@ func (sb *statisticsBuilder) buildJoin( case opt.AntiJoinOp, opt.AntiJoinApplyOp: s.RowCount = leftStats.RowCount - s.Selectivity = 1 + s.Selectivity = props.OneSelectivity } return } @@ -1160,7 +1160,7 @@ func (sb *statisticsBuilder) buildJoin( // This is like an index join, so apply a selectivity that will result // in leftStats.RowCount rows. if rightStats.RowCount != 0 { - s.ApplySelectivity(1 / rightStats.RowCount) + s.ApplySelectivity(props.MakeSelectivity(1 / rightStats.RowCount)) } } else { // Add the self join columns to equivReps so they are included in the @@ -1185,7 +1185,7 @@ func (sb *statisticsBuilder) buildJoin( s.ApplySelectivity(sb.selectivityFromNullsRemoved(join, relProps.NotNullCols, constrainedCols)) // Adjust the selectivity so we don't double-count the histogram columns. - s.ApplySelectivity(1.0 / sb.selectivityFromSingleColDistinctCounts(histCols, join, s)) + s.UnapplySelectivity(sb.selectivityFromSingleColDistinctCounts(histCols, join, s)) // Update distinct counts based on equivalencies; this should happen after // selectivityFromMultiColDistinctCounts and selectivityFromEquivalencies. @@ -1238,7 +1238,7 @@ func (sb *statisticsBuilder) buildJoin( switch h.joinType { case opt.AntiJoinOp, opt.AntiJoinApplyOp: s.RowCount = max(leftStats.RowCount-s.RowCount, epsilon) - s.Selectivity = max(1-s.Selectivity, epsilon) + s.Selectivity = props.MakeSelectivity(1 - s.Selectivity.AsFloat()) // Converting column stats is error-prone. If any column stats are needed, // colStatJoin will use the selectivity calculated above to estimate the @@ -1421,7 +1421,7 @@ func (sb *statisticsBuilder) colStatJoin(colSet opt.ColSet, join RelExpr) *props rightNullCount, rightProps.Stats.RowCount, s.RowCount, - s.Selectivity*inputRowCount, + s.Selectivity.AsFloat()*inputRowCount, ) // Ensure distinct count is non-zero. @@ -1594,7 +1594,7 @@ func (sb *statisticsBuilder) colStatIndexJoin( // of any filters on the input. inputStats := &inputProps.Stats tableStats := sb.makeTableStatistics(join.Table) - selectivity := inputStats.RowCount / tableStats.RowCount + selectivity := props.MakeSelectivity(inputStats.RowCount / tableStats.RowCount) lookupColStat.ApplySelectivity(selectivity, tableStats.RowCount) // Multiply the distinct counts in case colStat.DistinctCount is @@ -1996,7 +1996,7 @@ func (sb *statisticsBuilder) buildLimit(limit *LimitExpr, relProps *props.Relati hardLimit := *cnst.Value.(*tree.DInt) if hardLimit > 0 { s.RowCount = min(float64(hardLimit), inputStats.RowCount) - s.Selectivity = s.RowCount / inputStats.RowCount + s.Selectivity = props.MakeSelectivity(s.RowCount / inputStats.RowCount) } } @@ -2049,7 +2049,7 @@ func (sb *statisticsBuilder) buildOffset(offset *OffsetExpr, relProps *props.Rel } else if hardOffset > 0 { s.RowCount = inputStats.RowCount - float64(hardOffset) } - s.Selectivity = s.RowCount / inputStats.RowCount + s.Selectivity = props.MakeSelectivity(s.RowCount / inputStats.RowCount) } sb.finalizeFromCardinality(relProps) @@ -2577,7 +2577,7 @@ func (sb *statisticsBuilder) finalizeFromRowCountAndDistinctCounts( if colStat.Histogram != nil { valuesCount := colStat.Histogram.ValuesCount() if valuesCount > rowCount { - colStat.Histogram = colStat.Histogram.ApplySelectivity(rowCount / valuesCount) + colStat.Histogram = colStat.Histogram.ApplySelectivity(props.MakeSelectivity(rowCount / valuesCount)) } } } @@ -2895,7 +2895,7 @@ func (sb *statisticsBuilder) filterRelExpr( s.ApplySelectivity(sb.selectivityFromNullsRemoved(e, notNullCols, constrainedCols)) // Adjust the selectivity so we don't double-count the histogram columns. - s.ApplySelectivity(1.0 / sb.selectivityFromSingleColDistinctCounts(histCols, e, s)) + s.UnapplySelectivity(sb.selectivityFromSingleColDistinctCounts(histCols, e, s)) // Update distinct and null counts based on equivalencies; this should // happen after selectivityFromMultiColDistinctCounts and @@ -3491,7 +3491,7 @@ func (sb *statisticsBuilder) updateDistinctNullCountsFromEquivalency( // func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( cols opt.ColSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { +) (selectivity props.Selectivity) { // Respect the session setting OptimizerUseMultiColStats. if !sb.evalCtx.SessionData.OptimizerUseMultiColStats { return sb.selectivityFromSingleColDistinctCounts(cols, e, s) @@ -3502,11 +3502,11 @@ func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( // First calculate the selectivity from equation (1) (see function comment), // and collect the inputs to equation (2). - singleColSelectivity := 1.0 + singleColSelectivity := props.OneSelectivity newDistinctProduct, oldDistinctProduct := 1.0, 1.0 maxNewDistinct, maxOldDistinct := float64(0), float64(0) multiColNullCount := -1.0 - minLocalSel := math.MaxFloat64 + minLocalSel := props.OneSelectivity for col, ok := cols.Next(0); ok; col, ok = cols.Next(col + 1) { colStat, ok := s.ColStats.Lookup(opt.MakeColSet(col)) if !ok { @@ -3516,11 +3516,11 @@ func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( inputColStat, inputStats := sb.colStatFromInput(colStat.Cols, e) localSel := sb.selectivityFromDistinctCount(colStat, inputColStat, inputStats.RowCount) - singleColSelectivity *= localSel + singleColSelectivity.Multiply(localSel) // Don't bother including columns in the multi-column calculation that // don't contribute to the selectivity. - if localSel == 1 { + if localSel == props.OneSelectivity { multiColSet.Remove(col) continue } @@ -3534,9 +3534,7 @@ func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( if inputColStat.DistinctCount > maxOldDistinct { maxOldDistinct = inputColStat.DistinctCount } - if localSel < minLocalSel { - minLocalSel = localSel - } + minLocalSel = props.MinSelectivity(localSel, minLocalSel) if multiColNullCount < 0 { multiColNullCount = inputStats.RowCount } @@ -3601,16 +3599,14 @@ func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( selLowDistinctCountCols := sb.selectivityFromMultiColDistinctCounts( lowDistinctCountCols, e, s, ) - if selLowDistinctCountCols < minLocalSel { - minLocalSel = selLowDistinctCountCols - } + minLocalSel = props.MinSelectivity(minLocalSel, selLowDistinctCountCols) } } - multiColSelectivity = min(multiColSelectivity, minLocalSel) + multiColSelectivity = props.MinSelectivity(multiColSelectivity, minLocalSel) // As described in the function comment, we actually return a weighted sum // of multi-column and single-column selectivity estimates. - return (1-multiColWeight)*singleColSelectivity + multiColWeight*multiColSelectivity + return props.MakeSelectivity((1-multiColWeight)*singleColSelectivity.AsFloat() + multiColWeight*multiColSelectivity.AsFloat()) } // selectivityFromSingleColDistinctCounts calculates the selectivity of a @@ -3620,8 +3616,8 @@ func (sb *statisticsBuilder) selectivityFromMultiColDistinctCounts( // comment above that function for details. func (sb *statisticsBuilder) selectivityFromSingleColDistinctCounts( cols opt.ColSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { - selectivity = 1.0 +) (selectivity props.Selectivity) { + selectivity = props.OneSelectivity for col, ok := cols.Next(0); ok; col, ok = cols.Next(col + 1) { colStat, ok := s.ColStats.Lookup(opt.MakeColSet(col)) if !ok { @@ -3629,12 +3625,12 @@ func (sb *statisticsBuilder) selectivityFromSingleColDistinctCounts( } inputColStat, inputStats := sb.colStatFromInput(colStat.Cols, e) - selectivity *= sb.selectivityFromDistinctCount(colStat, inputColStat, inputStats.RowCount) + selectivity.Multiply(sb.selectivityFromDistinctCount(colStat, inputColStat, inputStats.RowCount)) } // Avoid setting selectivity to 0. The stats may be stale, and we // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } // selectivityFromDistinctCount calculates the selectivity of a filter by using @@ -3642,7 +3638,7 @@ func (sb *statisticsBuilder) selectivityFromSingleColDistinctCounts( // columns before and after the filter was applied. func (sb *statisticsBuilder) selectivityFromDistinctCount( colStat, inputColStat *props.ColumnStatistic, inputRowCount float64, -) float64 { +) props.Selectivity { newDistinct := colStat.DistinctCount oldDistinct := inputColStat.DistinctCount @@ -3656,8 +3652,8 @@ func (sb *statisticsBuilder) selectivityFromDistinctCount( } // Calculate the selectivity of the predicate. - nonNullSelectivity := fraction(newDistinct, oldDistinct) - nullSelectivity := fraction(colStat.NullCount, inputColStat.NullCount) + nonNullSelectivity := props.MakeSelectivity(newDistinct / oldDistinct) + nullSelectivity := props.MakeSelectivity(colStat.NullCount / inputColStat.NullCount) return sb.predicateSelectivity( nonNullSelectivity, nullSelectivity, inputColStat.NullCount, inputRowCount, ) @@ -3671,8 +3667,8 @@ func (sb *statisticsBuilder) selectivityFromDistinctCount( // (# values in histogram after filter) / (# values in histogram before filter). func (sb *statisticsBuilder) selectivityFromHistograms( cols opt.ColSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { - selectivity = 1.0 +) (selectivity props.Selectivity) { + selectivity = props.OneSelectivity for col, ok := cols.Next(0); ok; col, ok = cols.Next(col + 1) { colStat, ok := s.ColStats.Lookup(opt.MakeColSet(col)) if !ok { @@ -3690,16 +3686,14 @@ func (sb *statisticsBuilder) selectivityFromHistograms( oldCount := oldHist.ValuesCount() // Calculate the selectivity of the predicate. - nonNullSelectivity := fraction(newCount, oldCount) - nullSelectivity := fraction(colStat.NullCount, inputColStat.NullCount) - selectivity *= sb.predicateSelectivity( + nonNullSelectivity := props.MakeSelectivity(newCount / oldCount) + nullSelectivity := props.MakeSelectivity(colStat.NullCount / inputColStat.NullCount) + selectivity.Multiply(sb.predicateSelectivity( nonNullSelectivity, nullSelectivity, inputColStat.NullCount, inputStats.RowCount, - ) + )) } - // Avoid setting selectivity to 0. The stats may be stale, and we - // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } // selectivityFromNullsRemoved calculates the selectivity from null-rejecting @@ -3708,23 +3702,21 @@ func (sb *statisticsBuilder) selectivityFromHistograms( // should be designated by ignoreCols. func (sb *statisticsBuilder) selectivityFromNullsRemoved( e RelExpr, notNullCols opt.ColSet, ignoreCols opt.ColSet, -) (selectivity float64) { - selectivity = 1.0 +) (selectivity props.Selectivity) { + selectivity = props.OneSelectivity notNullCols.ForEach(func(col opt.ColumnID) { if !ignoreCols.Contains(col) { inputColStat, inputStats := sb.colStatFromInput(opt.MakeColSet(col), e) - selectivity *= sb.predicateSelectivity( - 1, /* nonNullSelectivity */ - 0, /* nullSelectivity */ + selectivity.Multiply(sb.predicateSelectivity( + props.OneSelectivity, /* nonNullSelectivity */ + props.ZeroSelectivity, /* nullSelectivity */ inputColStat.NullCount, inputStats.RowCount, - ) + )) } }) - // Avoid setting selectivity to 0. The stats may be stale, and we - // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } // predicateSelectivity calculates the selectivity of a predicate, using the @@ -3739,35 +3731,33 @@ func (sb *statisticsBuilder) selectivityFromNullsRemoved( // (fraction of null values preserved) * (number of null input rows) // func (sb *statisticsBuilder) predicateSelectivity( - nonNullSelectivity, nullSelectivity, inputNullCount, inputRowCount float64, -) float64 { - outRowCount := nonNullSelectivity*(inputRowCount-inputNullCount) + nullSelectivity*inputNullCount - sel := outRowCount / inputRowCount + nonNullSelectivity, nullSelectivity props.Selectivity, inputNullCount, inputRowCount float64, +) props.Selectivity { + outRowCount := nonNullSelectivity.AsFloat()*(inputRowCount-inputNullCount) + nullSelectivity.AsFloat()*inputNullCount + sel := props.MakeSelectivity(outRowCount / inputRowCount) - // Avoid setting selectivity to 0. The stats may be stale, and we - // can end up with weird and inefficient plans if we estimate 0 rows. - return max(sel, epsilon) + return sel } // selectivityFromEquivalencies determines the selectivity of equality // constraints. It must be called before applyEquivalencies. func (sb *statisticsBuilder) selectivityFromEquivalencies( equivReps opt.ColSet, filterFD *props.FuncDepSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { - selectivity = 1.0 +) (selectivity props.Selectivity) { + selectivity = props.OneSelectivity equivReps.ForEach(func(i opt.ColumnID) { equivGroup := filterFD.ComputeEquivGroup(i) - selectivity *= sb.selectivityFromEquivalency(equivGroup, e, s) + selectivity.Multiply(sb.selectivityFromEquivalency(equivGroup, e, s)) }) // Avoid setting selectivity to 0. The stats may be stale, and we // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } func (sb *statisticsBuilder) selectivityFromEquivalency( equivGroup opt.ColSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { +) (selectivity props.Selectivity) { // Find the maximum input distinct count for all columns in this equivalency // group. maxDistinctCount := float64(0) @@ -3789,7 +3779,7 @@ func (sb *statisticsBuilder) selectivityFromEquivalency( // The selectivity of an equality condition var1=var2 is // 1/max(distinct(var1), distinct(var2)). - return fraction(1, maxDistinctCount) + return props.MakeSelectivity(1 / maxDistinctCount) } // selectivityFromEquivalenciesSemiJoin determines the selectivity of equality @@ -3799,23 +3789,23 @@ func (sb *statisticsBuilder) selectivityFromEquivalenciesSemiJoin( filterFD *props.FuncDepSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { - selectivity = 1.0 +) (selectivity props.Selectivity) { + selectivity = props.OneSelectivity equivReps.ForEach(func(i opt.ColumnID) { equivGroup := filterFD.ComputeEquivGroup(i) - selectivity *= sb.selectivityFromEquivalencySemiJoin( + selectivity.Multiply(sb.selectivityFromEquivalencySemiJoin( equivGroup, leftOutputCols, rightOutputCols, e, s, - ) + )) }) // Avoid setting selectivity to 0. The stats may be stale, and we // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } func (sb *statisticsBuilder) selectivityFromEquivalencySemiJoin( equivGroup, leftOutputCols, rightOutputCols opt.ColSet, e RelExpr, s *props.Statistics, -) (selectivity float64) { +) (selectivity props.Selectivity) { // Find the minimum (maximum) input distinct count for all columns in this // equivalency group from the right (left). minDistinctCountRight := math.MaxFloat64 @@ -3842,23 +3832,23 @@ func (sb *statisticsBuilder) selectivityFromEquivalencySemiJoin( maxDistinctCountLeft = s.RowCount } - return fraction(minDistinctCountRight, maxDistinctCountLeft) + return props.MakeSelectivity(minDistinctCountRight / maxDistinctCountLeft) } func (sb *statisticsBuilder) selectivityFromInvertedJoinCondition( e RelExpr, s *props.Statistics, -) (selectivity float64) { - return unknownInvertedJoinSelectivity +) (selectivity props.Selectivity) { + return props.MakeSelectivity(unknownInvertedJoinSelectivity) } func (sb *statisticsBuilder) selectivityFromUnappliedConjuncts( numUnappliedConjuncts float64, -) (selectivity float64) { - selectivity = math.Pow(unknownFilterSelectivity, numUnappliedConjuncts) +) (selectivity props.Selectivity) { + selectivity = props.MakeSelectivity(math.Pow(unknownFilterSelectivity, numUnappliedConjuncts)) // Avoid setting selectivity to 0. The stats may be stale, and we // can end up with weird and inefficient plans if we estimate 0 rows. - return max(selectivity, epsilon) + return selectivity } // tryReduceCols is used to determine which columns to use for selectivity diff --git a/pkg/sql/opt/memo/testdata/stats/index-join b/pkg/sql/opt/memo/testdata/stats/index-join index e7c2c4197b27..830851c62c7c 100644 --- a/pkg/sql/opt/memo/testdata/stats/index-join +++ b/pkg/sql/opt/memo/testdata/stats/index-join @@ -185,7 +185,7 @@ SELECT * FROM a WHERE s = 'foo' AND x + y = 10 select ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) ├── immutable - ├── stats: [rows=33.3333333, distinct(1)=33.3333333, null(1)=0, distinct(2)=28.5927601, null(2)=16.6666667, distinct(3)=1, null(3)=0, distinct(4)=30.9412676, null(4)=0, distinct(1-3)=33.3333333, null(1-3)=0] + ├── stats: [rows=33.3333334, distinct(1)=33.3333334, null(1)=0, distinct(2)=28.5927601, null(2)=16.6666667, distinct(3)=1, null(3)=0, distinct(4)=30.9412677, null(4)=0, distinct(1-3)=33.3333334, null(1-3)=0] ├── key: (1) ├── fd: ()-->(3), (1)-->(2,4), (4)-->(1,2) ├── index-join a @@ -207,7 +207,7 @@ SELECT * FROM a WHERE s = 'foo' ---- index-join a ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) - ├── stats: [rows=100, distinct(1)=100, null(1)=0, distinct(2)=64.4232893, null(2)=50, distinct(3)=1, null(3)=0, distinct(1-3)=100, null(1-3)=0] + ├── stats: [rows=100, distinct(1)=100, null(1)=0, distinct(2)=64.4232894, null(2)=50, distinct(3)=1, null(3)=0, distinct(1-3)=100, null(1-3)=0] ├── key: (1) ├── fd: ()-->(3), (1)-->(2,4), (4)-->(1,2) └── scan a@secondary @@ -231,7 +231,7 @@ SELECT * FROM a WHERE (s = 'foo' OR s = 'bar') AND s IS NOT NULL ---- index-join a ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) - ├── stats: [rows=200, distinct(1)=200, null(1)=0, distinct(2)=88.4618791, null(2)=100, distinct(3)=2, null(3)=0, distinct(2,3)=176.923758, null(2,3)=0, distinct(1-3)=200, null(1-3)=0] + ├── stats: [rows=200, distinct(1)=200, null(1)=0, distinct(2)=88.4618792, null(2)=100, distinct(3)=2, null(3)=0, distinct(2,3)=176.923758, null(2,3)=0, distinct(1-3)=200, null(1-3)=0] ├── key: (1) ├── fd: (1)-->(2-4), (3,4)-->(1,2) └── scan a@secondary diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-geo b/pkg/sql/opt/memo/testdata/stats/inverted-geo index 834765e4c4fb..5e7406760266 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-geo +++ b/pkg/sql/opt/memo/testdata/stats/inverted-geo @@ -183,7 +183,7 @@ project │ │ ├── columns: rowid:3(int!null) g_inverted_key:5(geometry!null) │ │ ├── inverted constraint: /5/3 │ │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ │ ├── stats: [rows=7e-07, distinct(3)=1.99999931e-07, null(3)=0, distinct(5)=7e-07, null(5)=0] + │ │ ├── stats: [rows=7e-07, distinct(3)=7e-07, null(3)=0, distinct(5)=7e-07, null(5)=0] │ │ │ histogram(5)= │ │ ├── key: (3) │ │ └── fd: (3)-->(5) @@ -402,7 +402,7 @@ project │ │ ├── columns: rowid:3(int!null) g_inverted_key:5(geometry!null) │ │ ├── inverted constraint: /5/3 │ │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ │ ├── stats: [rows=7e-07, distinct(3)=1.99999931e-07, null(3)=0, distinct(5)=7e-07, null(5)=0] + │ │ ├── stats: [rows=7e-07, distinct(3)=7e-07, null(3)=0, distinct(5)=7e-07, null(5)=0] │ │ │ histogram(5)= │ │ ├── key: (3) │ │ └── fd: (3)-->(5) diff --git a/pkg/sql/opt/memo/testdata/stats/limit b/pkg/sql/opt/memo/testdata/stats/limit index ff0dc0ebbe1e..a2d298abca3e 100644 --- a/pkg/sql/opt/memo/testdata/stats/limit +++ b/pkg/sql/opt/memo/testdata/stats/limit @@ -214,13 +214,13 @@ limit ├── fd: ()-->(3), (1)-->(2,4), (4)-->(1,2) ├── project │ ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) - │ ├── stats: [rows=100, distinct(2)=92.7652197, null(2)=50, distinct(3)=1, null(3)=0, distinct(2,3)=92.7652197, null(2,3)=0] + │ ├── stats: [rows=100, distinct(2)=92.7652198, null(2)=50, distinct(3)=1, null(3)=0, distinct(2,3)=92.7652198, null(2,3)=0] │ ├── key: (1) │ ├── fd: ()-->(3), (1)-->(2,4), (4)-->(1,2) │ ├── limit hint: 5.00 │ └── select │ ├── columns: x:1(int!null) y:2(int) s:3(string!null) d:4(decimal!null) crdb_internal_mvcc_timestamp:5(decimal) - │ ├── stats: [rows=100, distinct(2)=92.7652197, null(2)=50, distinct(3)=1, null(3)=0, distinct(2,3)=92.7652197, null(2,3)=0] + │ ├── stats: [rows=100, distinct(2)=92.7652198, null(2)=50, distinct(3)=1, null(3)=0, distinct(2,3)=92.7652198, null(2,3)=0] │ ├── key: (1) │ ├── fd: ()-->(3), (1)-->(2,4,5), (4)-->(1,2,5) │ ├── limit hint: 5.00 diff --git a/pkg/sql/opt/memo/testdata/stats/lookup-join b/pkg/sql/opt/memo/testdata/stats/lookup-join index 4d8f20b16e50..1791bbf8ea92 100644 --- a/pkg/sql/opt/memo/testdata/stats/lookup-join +++ b/pkg/sql/opt/memo/testdata/stats/lookup-join @@ -245,13 +245,13 @@ left-join (lookup def) ├── columns: a:1(int!null) b:2(int) c:3(int!null) d:5(int) e:6(int) f:7(int) g:8(float) ├── key columns: [7 6] = [7 6] ├── lookup columns are key - ├── stats: [rows=100, distinct(5)=10, null(5)=90, distinct(8)=9.95021575, null(8)=91] + ├── stats: [rows=100, distinct(5)=10.0000001, null(5)=89.9999999, distinct(8)=9.95021585, null(8)=90.9999999] ├── key: (1,3,6,7) ├── fd: (1,3)-->(2), (6,7)-->(5,8) ├── left-join (lookup def@d_idx) │ ├── columns: a:1(int!null) b:2(int) c:3(int!null) d:5(int) e:6(int) f:7(int) │ ├── key columns: [1] = [5] - │ ├── stats: [rows=100, distinct(5)=10, null(5)=90] + │ ├── stats: [rows=100, distinct(5)=10.0000001, null(5)=89.9999999] │ ├── key: (1,3,6,7) │ ├── fd: (1,3)-->(2), (6,7)-->(5) │ ├── scan abc @@ -270,7 +270,7 @@ SELECT * FROM abc LEFT JOIN DEF ON a = e AND b = 3 ---- right-join (hash) ├── columns: a:1(int!null) b:2(int) c:3(int!null) d:5(int) e:6(int) f:7(int) g:8(float) - ├── stats: [rows=100, distinct(6)=100, null(6)=0, distinct(8)=95.1671064, null(8)=1] + ├── stats: [rows=100.000001, distinct(6)=100, null(6)=0, distinct(8)=95.1671073, null(8)=1.00000001] ├── key: (1,3,6,7) ├── fd: (1,3)-->(2), (6,7)-->(5,8) ├── scan def diff --git a/pkg/sql/opt/memo/testdata/stats/multi-column-inverted-geo b/pkg/sql/opt/memo/testdata/stats/multi-column-inverted-geo index 3e6dbd4f2dc4..50d38cde5686 100644 --- a/pkg/sql/opt/memo/testdata/stats/multi-column-inverted-geo +++ b/pkg/sql/opt/memo/testdata/stats/multi-column-inverted-geo @@ -107,7 +107,7 @@ project │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] │ ├── flags: force-index=m - │ ├── stats: [rows=153.552632, distinct(1)=43.8721805, null(1)=0, distinct(3)=1, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=3, null(3,6)=0] + │ ├── stats: [rows=153.552632, distinct(1)=43.8721804, null(1)=0, distinct(3)=1, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=3, null(3,6)=0] │ │ histogram(3)= 0 100 │ │ <--- 'banana' │ │ histogram(6)= 0 0 25.592 0 25.592 51.184 25.592 0 0 0 25.592 0 @@ -158,7 +158,7 @@ project │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] │ ├── flags: force-index=p - │ ├── stats: [rows=153.552632, distinct(1)=43.8721805, null(1)=0, distinct(3)=1, null(3)=0, distinct(7)=3, null(7)=0, distinct(3,7)=3, null(3,7)=0] + │ ├── stats: [rows=153.552632, distinct(1)=43.8721804, null(1)=0, distinct(3)=1, null(3)=0, distinct(7)=3, null(7)=0, distinct(3,7)=3, null(3,7)=0] │ │ histogram(3)= 0 100 │ │ <--- 'banana' │ │ histogram(7)= 0 0 25.592 0 25.592 51.184 25.592 0 0 0 25.592 0 diff --git a/pkg/sql/opt/memo/testdata/stats/partial-index-scan b/pkg/sql/opt/memo/testdata/stats/partial-index-scan index a1a4fdc1bd04..78c7b4e416f7 100644 --- a/pkg/sql/opt/memo/testdata/stats/partial-index-scan +++ b/pkg/sql/opt/memo/testdata/stats/partial-index-scan @@ -54,12 +54,12 @@ SELECT * FROM a WHERE s = 'foo' ---- index-join a ├── columns: k:1(int!null) i:2(int) s:3(string!null) t:4(string) - ├── stats: [rows=96.4285714, distinct(3)=1, null(3)=0] + ├── stats: [rows=96.4285715, distinct(3)=1, null(3)=0] ├── key: (1) ├── fd: ()-->(3), (1)-->(2,4) └── scan a@idx,partial ├── columns: k:1(int!null) i:2(int) - ├── stats: [rows=96.4285714, distinct(3)=1, null(3)=0] + ├── stats: [rows=96.4285715, distinct(3)=1, null(3)=0] ├── key: (1) └── fd: (1)-->(2) @@ -1271,17 +1271,17 @@ SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND project ├── columns: k:1(int!null) ├── immutable - ├── stats: [rows=8.54700855] + ├── stats: [rows=8.54700856] ├── key: (1) └── select ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) ├── immutable - ├── stats: [rows=8.54700855, distinct(2)=7, null(2)=0, distinct(3)=3, null(3)=0] + ├── stats: [rows=8.54700856, distinct(2)=7, null(2)=0, distinct(3)=3, null(3)=0] ├── key: (1) ├── fd: (1)-->(2,3) ├── index-join spatial │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) - │ ├── stats: [rows=8.54700855] + │ ├── stats: [rows=8.54700856] │ ├── key: (1) │ ├── fd: (1)-->(2,3) │ └── inverted-filter @@ -1294,7 +1294,7 @@ project │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] │ ├── pre-filterer expression │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] - │ ├── stats: [rows=8.54700855] + │ ├── stats: [rows=8.54700856] │ ├── key: (1) │ └── scan spatial@p,partial │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) @@ -1303,7 +1303,7 @@ project │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] - │ ├── stats: [rows=8.54700855, distinct(1)=8.54700855, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700855, null(6)=0] + │ ├── stats: [rows=8.54700856, distinct(1)=8.54700856, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700856, null(6)=0] │ ├── key: (1) │ └── fd: (1)-->(6) └── filters @@ -1315,17 +1315,17 @@ SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND project ├── columns: k:1(int!null) ├── immutable - ├── stats: [rows=2.84900285] + ├── stats: [rows=2.84900286] ├── key: (1) └── select ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) ├── immutable - ├── stats: [rows=2.84900285, distinct(2)=2.84900285, null(2)=0, distinct(3)=1, null(3)=0] + ├── stats: [rows=2.84900286, distinct(2)=2.84900286, null(2)=0, distinct(3)=1, null(3)=0] ├── key: (1) ├── fd: ()-->(3), (1)-->(2) ├── index-join spatial │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) - │ ├── stats: [rows=8.54700855] + │ ├── stats: [rows=8.54700856] │ ├── key: (1) │ ├── fd: (1)-->(2,3) │ └── inverted-filter @@ -1338,7 +1338,7 @@ project │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] │ ├── pre-filterer expression │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] - │ ├── stats: [rows=8.54700855] + │ ├── stats: [rows=8.54700856] │ ├── key: (1) │ └── scan spatial@p,partial │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) @@ -1347,7 +1347,7 @@ project │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] - │ ├── stats: [rows=8.54700855, distinct(1)=8.54700855, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700855, null(6)=0] + │ ├── stats: [rows=8.54700856, distinct(1)=8.54700856, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700856, null(6)=0] │ ├── key: (1) │ └── fd: (1)-->(6) └── filters diff --git a/pkg/sql/opt/memo/testdata/stats/scan b/pkg/sql/opt/memo/testdata/stats/scan index ed025f546e27..be10bfbd7b9e 100644 --- a/pkg/sql/opt/memo/testdata/stats/scan +++ b/pkg/sql/opt/memo/testdata/stats/scan @@ -1048,7 +1048,7 @@ project │ └── scan t47742@b_idx │ ├── columns: t47742.b:2(bool!null) rowid:3(int!null) │ ├── constraint: /-2/3: [/true - /true] - │ ├── stats: [rows=2640.64496, distinct(2)=1.00246926, null(2)=0] + │ ├── stats: [rows=2640.64496, distinct(2)=11, null(2)=0] │ │ histogram(2)= 0 0 0.0021284 2640.6 │ │ <--- false ----------- true │ ├── key: (3) @@ -1494,7 +1494,7 @@ AND f > 0 ---- select ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null) - ├── stats: [rows=27.8153382, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=27.8153382, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=27.8153382, null(2,3,5,6)=0] + ├── stats: [rows=27.8153383, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=27.8153383, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=27.8153383, null(2,3,5,6)=0] ├── fd: ()-->(2,3) ├── index-join multi_col │ ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float) @@ -1525,7 +1525,7 @@ AND f > 0 ---- select ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null) - ├── stats: [rows=27.8153382, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=27.8153382, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=27.8153382, null(2,3,5,6)=0] + ├── stats: [rows=27.8153383, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=27.8153383, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=27.8153383, null(2,3,5,6)=0] ├── fd: ()-->(2,3) ├── index-join multi_col │ ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float) @@ -1833,7 +1833,7 @@ AND f > 0 ---- select ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null) - ├── stats: [rows=55.6195503, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=55.6195503, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=55.6195503, null(2,3,5,6)=0] + ├── stats: [rows=55.6195504, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=55.6195504, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=55.6195504, null(2,3,5,6)=0] │ histogram(2)= 0 55.62 │ <--- true ├── fd: ()-->(2,3) @@ -1866,7 +1866,7 @@ AND f > 0 ---- select ├── columns: a:1(uuid) b:2(bool!null) c:3(int!null) d:4(string) e:5(int!null) f:6(float!null) - ├── stats: [rows=55.6195503, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=55.6195503, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=55.6195503, null(2,3,5,6)=0] + ├── stats: [rows=55.6195504, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(5)=5, null(5)=0, distinct(6)=55.6195504, null(6)=0, distinct(2,3)=1, null(2,3)=0, distinct(2,3,5,6)=55.6195504, null(2,3,5,6)=0] │ histogram(2)= 0 55.62 │ <--- true ├── fd: ()-->(2,3) @@ -1904,7 +1904,7 @@ AND f = 0 ---- select ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null) - ├── stats: [rows=17.9784037, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(4)=1, null(4)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(1,2,4-6)=1, null(1,2,4-6)=0] + ├── stats: [rows=17.9784056, distinct(1)=1, null(1)=0, distinct(2)=1, null(2)=0, distinct(4)=1, null(4)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(1,2,4-6)=1, null(1,2,4-6)=0] │ histogram(2)= 0 17.978 │ <--- true │ histogram(4)= 0 17.978 @@ -1912,13 +1912,13 @@ select ├── fd: ()-->(1,2,4-6) ├── index-join multi_col │ ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float) - │ ├── stats: [rows=1.99072309] + │ ├── stats: [rows=1.9907231] │ ├── fd: ()-->(2,5,6) │ └── scan multi_col@bef_idx │ ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null) │ ├── constraint: /2/5/6/7: [/true/5/0.0 - /true/5/0.0] │ ├── flags: force-index=bef_idx - │ ├── stats: [rows=1.99072309, distinct(2)=1, null(2)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(2,5,6)=1, null(2,5,6)=0] + │ ├── stats: [rows=1.9907231, distinct(2)=1, null(2)=0, distinct(5)=1, null(5)=0, distinct(6)=1, null(6)=0, distinct(2,5,6)=1, null(2,5,6)=0] │ │ histogram(2)= 0 1.9907 │ │ <--- true │ ├── key: (7) @@ -1937,7 +1937,7 @@ AND f = 0 ---- select ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null) - ├── stats: [rows=0.00179964001, distinct(1)=0.00179964001, null(1)=0, distinct(2)=0.00179964001, null(2)=0, distinct(4)=0.00179964001, null(4)=0, distinct(5)=0.00179964001, null(5)=0, distinct(6)=0.00179964001, null(6)=0, distinct(1,2,4-6)=0.00179964001, null(1,2,4-6)=0] + ├── stats: [rows=0.0017996402, distinct(1)=0.0017996402, null(1)=0, distinct(2)=0.0017996402, null(2)=0, distinct(4)=0.0017996402, null(4)=0, distinct(5)=0.0017996402, null(5)=0, distinct(6)=0.0017996402, null(6)=0, distinct(1,2,4-6)=0.0017996402, null(1,2,4-6)=0] │ histogram(2)= 0 0.0017996 │ <---- true -- │ histogram(4)= 0 0.0017996 @@ -1969,7 +1969,7 @@ AND f = 0 ---- select ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null) - ├── stats: [rows=3.60000002e-07, distinct(1)=3.60000002e-07, null(1)=0, distinct(2)=3.60000002e-07, null(2)=0, distinct(4)=3.60000002e-07, null(4)=0, distinct(5)=3.60000002e-07, null(5)=0, distinct(6)=3.60000002e-07, null(6)=0, distinct(1,2,4-6)=3.60000002e-07, null(1,2,4-6)=0] + ├── stats: [rows=3.6000022e-07, distinct(1)=3.6000022e-07, null(1)=0, distinct(2)=3.6000022e-07, null(2)=0, distinct(4)=3.6000022e-07, null(4)=0, distinct(5)=3.6000022e-07, null(5)=0, distinct(6)=3.6000022e-07, null(6)=0, distinct(1,2,4-6)=3.6000022e-07, null(1,2,4-6)=0] │ histogram(2)= 0 3.6e-07 │ <--- false │ histogram(4)= 0 3.6e-07 @@ -1977,12 +1977,12 @@ select ├── fd: ()-->(1,2,4-6) ├── index-join multi_col │ ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float) - │ ├── stats: [rows=3.61e-07] + │ ├── stats: [rows=3.6100018e-07] │ ├── fd: ()-->(1,2,4) │ └── scan multi_col@bad_idx │ ├── columns: a:1(uuid!null) b:2(bool!null) d:4(string!null) rowid:7(int!null) │ ├── constraint: /2/-1/4/7: [/false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'bar' - /false/'37685f26-4b07-40ba-9bbf-42916ed9bc61'/'bar'] - │ ├── stats: [rows=3.61e-07, distinct(1)=3.61e-07, null(1)=0, distinct(2)=3.61e-07, null(2)=0, distinct(4)=3.61e-07, null(4)=0, distinct(1,2,4)=3.61e-07, null(1,2,4)=0] + │ ├── stats: [rows=3.6100018e-07, distinct(1)=3.6100018e-07, null(1)=0, distinct(2)=3.6100018e-07, null(2)=0, distinct(4)=3.6100018e-07, null(4)=0, distinct(1,2,4)=3.6100018e-07, null(1,2,4)=0] │ │ histogram(2)= 0 3.61e-07 │ │ <--- false - │ │ histogram(4)= 0 3.61e-07 @@ -2003,7 +2003,7 @@ AND f = 0 ---- select ├── columns: a:1(uuid!null) b:2(bool!null) c:3(int) d:4(string!null) e:5(int!null) f:6(float!null) - ├── stats: [rows=0.00359640002, distinct(1)=0.00359640002, null(1)=0, distinct(2)=0.00359640002, null(2)=0, distinct(4)=0.00359640002, null(4)=0, distinct(5)=0.00359640002, null(5)=0, distinct(6)=0.00359640002, null(6)=0, distinct(1,2,4-6)=0.00359640002, null(1,2,4-6)=0] + ├── stats: [rows=0.0035964022, distinct(1)=0.0035964022, null(1)=0, distinct(2)=0.0035964022, null(2)=0, distinct(4)=0.0035964022, null(4)=0, distinct(5)=0.0035964022, null(5)=0, distinct(6)=0.0035964022, null(6)=0, distinct(1,2,4-6)=0.0035964022, null(1,2,4-6)=0] │ histogram(2)= 0 0.0035964 │ <---- false - │ histogram(4)= 0 0.0035964 @@ -2011,12 +2011,12 @@ select ├── fd: ()-->(1,2,4-6) ├── index-join multi_col │ ├── columns: a:1(uuid) b:2(bool) c:3(int) d:4(string) e:5(int) f:6(float) - │ ├── stats: [rows=0.000398224263] + │ ├── stats: [rows=0.000398224464] │ ├── fd: ()-->(2,5,6) │ └── scan multi_col@bef_idx │ ├── columns: b:2(bool!null) e:5(int!null) f:6(float!null) rowid:7(int!null) │ ├── constraint: /2/5/6/7: [/false/5/0.0 - /false/5/0.0] - │ ├── stats: [rows=0.000398224263, distinct(2)=0.000398224263, null(2)=0, distinct(5)=0.000398224263, null(5)=0, distinct(6)=0.000398224263, null(6)=0, distinct(2,5,6)=0.000398224263, null(2,5,6)=0] + │ ├── stats: [rows=0.000398224464, distinct(2)=0.000398224464, null(2)=0, distinct(5)=0.000398224464, null(5)=0, distinct(6)=0.000398224464, null(6)=0, distinct(2,5,6)=0.000398224464, null(2,5,6)=0] │ │ histogram(2)= 0 0.00039822 │ │ <---- false -- │ ├── key: (7) @@ -2071,7 +2071,7 @@ index-join t ├── constraint: /2/1 │ ├── [/NULL/5 - /NULL/5] │ └── [/5 - /5] - ├── stats: [rows=1.95200401, distinct(1)=1.95200401, null(1)=0, distinct(2)=1.95200401, null(2)=1.95200401] + ├── stats: [rows=1.95200406, distinct(1)=1.95200406, null(1)=0, distinct(2)=1.95200406, null(2)=1.95200406] ├── key: (1) └── fd: (1)-->(2) diff --git a/pkg/sql/opt/memo/testdata/stats/select b/pkg/sql/opt/memo/testdata/stats/select index e7a52f34fced..944a88d11caf 100644 --- a/pkg/sql/opt/memo/testdata/stats/select +++ b/pkg/sql/opt/memo/testdata/stats/select @@ -1074,7 +1074,7 @@ SELECT * FROM a WHERE y = 5 AND x + y < 10 ---- select ├── columns: x:1(int!null) y:2(int!null) - ├── stats: [rows=9.35672515, distinct(1)=9.35672515, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=9.35672515, null(1,2)=0] + ├── stats: [rows=9.35672524, distinct(1)=9.35672524, null(1)=0, distinct(2)=1, null(2)=0, distinct(1,2)=9.35672524, null(1,2)=0] ├── key: (1) ├── fd: ()-->(2) ├── scan a @@ -1140,7 +1140,7 @@ WHERE name='andy' ---- select ├── columns: id:1(int!null) name:2(string!null) state:3(string) order_id:5(int) item_id:6(int) customer_id:7(int!null) year:8(int) - ├── stats: [rows=1.84197978, distinct(2)=1, null(2)=0] + ├── stats: [rows=1.8419798, distinct(2)=1, null(2)=0] ├── fd: ()-->(2), (1)-->(3), (1)==(7), (7)==(1) ├── project │ ├── columns: id:1(int!null) name:2(string) state:3(string) order_id:5(int) item_id:6(int) customer_id:7(int!null) year:8(int) @@ -2462,7 +2462,7 @@ AND c29 = 1 AND c30 = 1 AND c31 = 1 AND c32 = 1 AND c33 = 1 ---- select ├── columns: c1:1(int!null) c2:2(int!null) c3:3(int!null) c4:4(int!null) c5:5(int!null) c6:6(int!null) c7:7(int!null) c8:8(int!null) c9:9(int!null) c10:10(int!null) c11:11(int!null) c12:12(int!null) c13:13(int!null) c14:14(int!null) c15:15(int!null) c16:16(int!null) c17:17(int!null) c18:18(int!null) c19:19(int!null) c20:20(int!null) c21:21(int!null) c22:22(int!null) c23:23(int!null) c24:24(int!null) c25:25(int!null) c26:26(int!null) c27:27(int!null) c28:28(int!null) c29:29(int!null) c30:30(int!null) c31:31(int!null) c32:32(int!null) c33:33(int!null) - ├── stats: [rows=9e-11, distinct(1)=9e-11, null(1)=0, distinct(2)=9e-11, null(2)=0, distinct(3)=9e-11, null(3)=0, distinct(4)=9e-11, null(4)=0, distinct(5)=9e-11, null(5)=0, distinct(6)=9e-11, null(6)=0, distinct(7)=9e-11, null(7)=0, distinct(8)=9e-11, null(8)=0, distinct(9)=9e-11, null(9)=0, distinct(10)=9e-11, null(10)=0, distinct(11)=9e-11, null(11)=0, distinct(12)=9e-11, null(12)=0, distinct(13)=9e-11, null(13)=0, distinct(14)=9e-11, null(14)=0, distinct(15)=9e-11, null(15)=0, distinct(16)=9e-11, null(16)=0, distinct(17)=9e-11, null(17)=0, distinct(18)=9e-11, null(18)=0, distinct(19)=9e-11, null(19)=0, distinct(20)=9e-11, null(20)=0, distinct(21)=9e-11, null(21)=0, distinct(22)=9e-11, null(22)=0, distinct(23)=9e-11, null(23)=0, distinct(24)=9e-11, null(24)=0, distinct(25)=9e-11, null(25)=0, distinct(26)=9e-11, null(26)=0, distinct(27)=9e-11, null(27)=0, distinct(28)=9e-11, null(28)=0, distinct(29)=9e-11, null(29)=0, distinct(30)=9e-11, null(30)=0, distinct(31)=9e-11, null(31)=0, distinct(32)=9e-11, null(32)=0, distinct(33)=9e-11, null(33)=0, distinct(1-33)=9e-11, null(1-33)=0] + ├── stats: [rows=1e-10, distinct(1)=1e-10, null(1)=0, distinct(2)=1e-10, null(2)=0, distinct(3)=1e-10, null(3)=0, distinct(4)=1e-10, null(4)=0, distinct(5)=1e-10, null(5)=0, distinct(6)=1e-10, null(6)=0, distinct(7)=1e-10, null(7)=0, distinct(8)=1e-10, null(8)=0, distinct(9)=1e-10, null(9)=0, distinct(10)=1e-10, null(10)=0, distinct(11)=1e-10, null(11)=0, distinct(12)=1e-10, null(12)=0, distinct(13)=1e-10, null(13)=0, distinct(14)=1e-10, null(14)=0, distinct(15)=1e-10, null(15)=0, distinct(16)=1e-10, null(16)=0, distinct(17)=1e-10, null(17)=0, distinct(18)=1e-10, null(18)=0, distinct(19)=1e-10, null(19)=0, distinct(20)=1e-10, null(20)=0, distinct(21)=1e-10, null(21)=0, distinct(22)=1e-10, null(22)=0, distinct(23)=1e-10, null(23)=0, distinct(24)=1e-10, null(24)=0, distinct(25)=1e-10, null(25)=0, distinct(26)=1e-10, null(26)=0, distinct(27)=1e-10, null(27)=0, distinct(28)=1e-10, null(28)=0, distinct(29)=1e-10, null(29)=0, distinct(30)=1e-10, null(30)=0, distinct(31)=1e-10, null(31)=0, distinct(32)=1e-10, null(32)=0, distinct(33)=1e-10, null(33)=0, distinct(1-33)=1e-10, null(1-33)=0] ├── fd: ()-->(1-33) ├── scan t │ ├── columns: c1:1(int) c2:2(int) c3:3(int) c4:4(int) c5:5(int) c6:6(int) c7:7(int) c8:8(int) c9:9(int) c10:10(int) c11:11(int) c12:12(int) c13:13(int) c14:14(int) c15:15(int) c16:16(int) c17:17(int) c18:18(int) c19:19(int) c20:20(int) c21:21(int) c22:22(int) c23:23(int) c24:24(int) c25:25(int) c26:26(int) c27:27(int) c28:28(int) c29:29(int) c30:30(int) c31:31(int) c32:32(int) c33:33(int) diff --git a/pkg/sql/opt/memo/testdata/stats/upsert b/pkg/sql/opt/memo/testdata/stats/upsert index 2f09acd3c32f..2bcc66e14ba3 100644 --- a/pkg/sql/opt/memo/testdata/stats/upsert +++ b/pkg/sql/opt/memo/testdata/stats/upsert @@ -109,24 +109,24 @@ with &1 │ │ ├── upsert_y:17 => xyz.y:2 │ │ └── upsert_z:18 => xyz.z:3 │ ├── volatile, mutations - │ ├── stats: [rows=9.94974874, distinct(1)=9.94974874, null(1)=0, distinct(2)=9.94974874, null(2)=0] + │ ├── stats: [rows=9.94974875, distinct(1)=9.94974875, null(1)=0, distinct(2)=9.94974875, null(2)=0] │ └── project │ ├── columns: upsert_x:16(string) upsert_y:17(int!null) upsert_z:18(float) a:5(int!null) b:6(string) column10:10(float) xyz.x:11(string) xyz.y:12(int) xyz.z:13(float) xyz.crdb_internal_mvcc_timestamp:14(decimal) y_new:15(int!null) │ ├── immutable - │ ├── stats: [rows=9.94974874, distinct(16)=9.94974874, null(16)=0, distinct(17)=9.94974874, null(17)=0] + │ ├── stats: [rows=9.94974875, distinct(16)=9.94974875, null(16)=0, distinct(17)=9.94974875, null(17)=0] │ ├── lax-key: (6,11) │ ├── fd: ()-->(10,15), (6)~~>(5), (11)-->(12-14), (6,11)-->(16), (5,11)-->(17), (6,11)~~>(5,17,18) │ ├── project │ │ ├── columns: y_new:15(int!null) a:5(int!null) b:6(string) column10:10(float) xyz.x:11(string) xyz.y:12(int) xyz.z:13(float) xyz.crdb_internal_mvcc_timestamp:14(decimal) │ │ ├── immutable - │ │ ├── stats: [rows=9.94974874, distinct(6,11)=9.94974874, null(6,11)=0, distinct(5,11,15)=9.94974874, null(5,11,15)=0] + │ │ ├── stats: [rows=9.94974875, distinct(6,11)=9.94974875, null(6,11)=0, distinct(5,11,15)=9.94974875, null(5,11,15)=0] │ │ ├── lax-key: (6,11) │ │ ├── fd: ()-->(10,15), (6)~~>(5), (11)-->(12-14) │ │ ├── left-join (hash) │ │ │ ├── columns: a:5(int!null) b:6(string) column10:10(float) xyz.x:11(string) xyz.y:12(int) xyz.z:13(float) xyz.crdb_internal_mvcc_timestamp:14(decimal) │ │ │ ├── multiplicity: left-rows(exactly-one), right-rows(zero-or-one) │ │ │ ├── immutable - │ │ │ ├── stats: [rows=9.94974874, distinct(11)=9.94974874, null(11)=0, distinct(5,11)=9.94974874, null(5,11)=0, distinct(6,11)=9.94974874, null(6,11)=0] + │ │ │ ├── stats: [rows=9.94974875, distinct(11)=9.94974875, null(11)=0, distinct(5,11)=9.94974875, null(5,11)=0, distinct(6,11)=9.94974875, null(6,11)=0] │ │ │ ├── lax-key: (6,11) │ │ │ ├── fd: ()-->(10), (6)~~>(5), (11)-->(12-14) │ │ │ ├── ensure-upsert-distinct-on @@ -134,20 +134,20 @@ with &1 │ │ │ │ ├── grouping columns: b:6(string) │ │ │ │ ├── error: "UPSERT or INSERT...ON CONFLICT command cannot affect row a second time" │ │ │ │ ├── immutable - │ │ │ │ ├── stats: [rows=9.94974874, distinct(5)=6.31184239, null(5)=0, distinct(6)=9.94974874, null(6)=0] + │ │ │ │ ├── stats: [rows=9.94974875, distinct(5)=6.31184239, null(5)=0, distinct(6)=9.94974875, null(6)=0] │ │ │ │ ├── lax-key: (6) │ │ │ │ ├── fd: ()-->(10), (6)~~>(5,10) │ │ │ │ ├── project │ │ │ │ │ ├── columns: column10:10(float) a:5(int!null) b:6(string) │ │ │ │ │ ├── immutable - │ │ │ │ │ ├── stats: [rows=9.94974874, distinct(6)=6.31184239, null(6)=0] + │ │ │ │ │ ├── stats: [rows=9.94974875, distinct(6)=6.31184239, null(6)=0] │ │ │ │ │ ├── fd: ()-->(10) │ │ │ │ │ ├── project │ │ │ │ │ │ ├── columns: a:5(int!null) b:6(string) - │ │ │ │ │ │ ├── stats: [rows=9.94974874, distinct(6)=6.31184239, null(6)=0] + │ │ │ │ │ │ ├── stats: [rows=9.94974875, distinct(6)=6.31184239, null(6)=0] │ │ │ │ │ │ └── select │ │ │ │ │ │ ├── columns: a:5(int!null) b:6(string) c:7(float!null) rowid:8(int!null) abc.crdb_internal_mvcc_timestamp:9(decimal) - │ │ │ │ │ │ ├── stats: [rows=9.94974874, distinct(6)=6.31184239, null(6)=0, distinct(7)=1, null(7)=0] + │ │ │ │ │ │ ├── stats: [rows=9.94974875, distinct(6)=6.31184239, null(6)=0, distinct(7)=1, null(7)=0] │ │ │ │ │ │ ├── key: (8) │ │ │ │ │ │ ├── fd: ()-->(7), (8)-->(5,6,9) │ │ │ │ │ │ ├── scan abc @@ -190,7 +190,7 @@ with &1 │ │ ├── xyz.x:1(string) => x:19(string) │ │ ├── xyz.y:2(int) => y:20(int) │ │ └── xyz.z:3(float) => z:21(float) - │ └── stats: [rows=9.94974874, distinct(19)=9.94974874, null(19)=0, distinct(20)=9.94974874, null(20)=0] + │ └── stats: [rows=9.94974875, distinct(19)=9.94974875, null(19)=0, distinct(20)=9.94974875, null(20)=0] └── filters └── y:20 = 10 [type=bool, outer=(20), constraints=(/20: [/10 - /10]; tight), fd=()-->(20)] diff --git a/pkg/sql/opt/memo/testdata/stats_quality/tpcc b/pkg/sql/opt/memo/testdata/stats_quality/tpcc index e5c6a5072fe7..cb64ddbebc2c 100644 --- a/pkg/sql/opt/memo/testdata/stats_quality/tpcc +++ b/pkg/sql/opt/memo/testdata/stats_quality/tpcc @@ -322,7 +322,7 @@ project ├── save-table-name: order_status_02_scan_3 ├── columns: c_id:1(int!null) c_d_id:2(int!null) c_w_id:3(int!null) c_first:4(varchar) c_last:6(varchar!null) ├── constraint: /3/2/6/4/1: [/2/2/'ANTIBARESE' - /2/2/'ANTIBARESE'] - ├── stats: [rows=2.12233702, distinct(1)=2.12159373, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(4)=2.11831349, null(4)=0, distinct(6)=1, null(6)=0, distinct(2,3,6)=1, null(2,3,6)=0] + ├── stats: [rows=2.12233702, distinct(1)=2.12233702, null(1)=0, distinct(2)=1, null(2)=0, distinct(3)=1, null(3)=0, distinct(4)=2.12233702, null(4)=0, distinct(6)=1, null(6)=0, distinct(2,3,6)=1, null(2,3,6)=0] │ histogram(1)= 0 0.00042447 0.0097628 0.00084893 0.010399 0.00084893 0.010399 0.00021223 0.009975 0.00084893 0.009975 0.0010612 0.010187 0.0010612 0.009975 0.0006367 0.010187 0.0012734 0.0097628 0.00084893 0.0097628 0.00084893 0.010399 0.0006367 0.010399 0.00042447 0.010187 0.0012734 0.010187 0.00084893 0.010399 0.0016979 0.010399 0.00084893 0.010399 0.0006367 0.009975 0.0006367 0.010187 0.00042447 0.010187 0.00084893 0.010399 0.0006367 0.010399 0.0012734 0.010399 0.00021223 0.009975 0.0006367 0.010187 0.0006367 0.010187 0.00084893 0.010399 0.00084893 0.0093383 0.0019101 0.0089138 0.0016979 0.010187 0.0014856 0.010187 0.0019101 0.0089138 0.0014856 0.009975 0.0010612 0.009975 0.0006367 0.0097628 0.0010612 0.0089138 0.0014856 0.010187 0.0006367 0.0097628 0.0006367 0.0097628 0.0010612 0.0097628 0.0006367 0.0097628 0.0006367 0.010187 0.00084893 0.010187 0.00042447 0.010187 0.00042447 0.009975 0.0006367 0.009975 0.00084893 0.009975 0.0010612 0.0097628 0.0012734 0.010187 0.0014856 0.010187 0.00021223 0.010187 0.0010612 0.0095505 0.0010612 0.0093383 0.0016979 0.0097628 0.0010612 0.010187 0.0006367 0.0095505 0.00084893 0.010187 0.00042447 0.0089138 0.0014856 0.010187 0.0010612 0.0097628 0.0010612 0.0095505 0.0010612 0.010187 0.0012734 0.0095505 0.00084893 0.0095505 0.00084893 0.009975 0.00084893 0.010187 0.0010612 0.009975 0.0010612 0.009975 0.0006367 0.009975 0.00084893 0.010187 0.0006367 0.0097628 0.0006367 0.009975 0.0006367 0.0093383 0.0014856 0.0095505 0.00084893 0.0097628 0.0006367 0.010187 0.0006367 0.010187 0.0006367 0.010187 0.00042447 0.0093383 0.0014856 0.010187 0.00042447 0.0097628 0.0014856 0.009975 0.0006367 0.0095505 0.0014856 0.010187 0.0012734 0.009975 0.00084893 0.009975 0.00084893 0.0097628 0.0010612 0.0097628 0.00084893 0.009975 0.0006367 0.010187 0.00084893 0.010187 0.00021223 0.010187 0.00021223 0.010187 0.0006367 0.009975 0.0010612 0.0095505 0.0010612 0.009126 0.0012734 0.0093383 0.0016979 0.0097628 0.0006367 0.0097628 0.0006367 0.009975 0.00042447 0.010187 0.00021223 0.009975 0.00084893 0.0097628 0.0016979 0.0095505 0.0012734 0.009975 0.00084893 0.009975 0.00042447 0.0097628 0.0012734 0.0095505 0.00084893 0.0093383 0.0010612 0.0097628 0.0006367 0.010187 0.00042447 0.0097628 0.0010612 0.009975 0.00084893 0.0097628 0.0006367 0.010187 0.00042447 0.0095505 0.00084893 0.010187 0.0006367 0.0093383 0.0010612 0.010187 0.0006367 0.0089138 0.0014856 0.010187 0.00084893 0.010187 0.0012734 0.009975 0.00042447 0.009126 0.0016979 0.010187 0.00042447 0.010187 0.0012734 0.0097628 0.0006367 0.009975 0.0006367 0.009975 0.00021223 0.0095505 0.0006367 0.009126 0.0014856 0.009975 0.00021223 0.0097628 0.0010612 0.009975 0.0006367 0.0093383 0.00084893 0.0097628 0.00084893 0.0093383 0.00084893 0.0097628 0.0012734 0.009975 0.00042447 0.009975 0.0010612 0.0087016 0.0019101 0.0087016 0.0023346 0.009126 0.0010612 0.0097628 0.00042447 0.009975 0.00084893 0.009975 0.00021223 0.0097628 0.0010612 0.0093383 0.00084893 0.0093383 0.00084893 0.0093383 0.0010612 0.009975 0.0006367 0.0097628 0.0006367 0.0097628 0.00042447 0.0097628 0.0014856 0.0095505 0.0006367 0.0097628 0.0006367 0.0097628 0.0006367 0.009126 0.0010612 0.0097628 0.00084893 0.0095505 0.0010612 0.0097628 0.0006367 0.009975 0.0006367 0.009975 0.00084893 0.009126 0.0012734 0.0095505 0.00084893 0.0095505 0.0010612 0.009126 0.0010612 0.0095505 0.0010612 0.0095505 0.0014856 0.009975 0.0014856 0.0095505 0.0006367 0.0097628 0.0014856 0.0097628 0.0010612 0.0093383 0.0006367 0.0095505 0.0006367 0.0097628 0.0006367 0.0097628 0.0006367 0.0087016 0.0012734 0.0095505 0.0014856 0.0097628 0.00021223 0.0089138 0.0014856 0.0095505 0.0010612 0.0087016 0.0012734 0.0097628 0.00084893 0.0095505 0.0012734 0.009126 0.0012734 0.0089138 0.00084893 0.0095505 0.00021223 0.0095505 0.0006367 0.0095505 0.00042447 0.0093383 0.0010612 0.0093383 0.00084893 0.0089138 0.0010612 0.0093383 0.00042447 0.0087016 0.0010612 0.0082771 0.0016979 0.0089138 0.0012734 0.0089138 0.00042447 0.0087016 0.00084893 │ <------ 2 ------------------ 22 ---------------- 40 ---------------- 56 ---------------- 72 --------------- 89 --------------- 104 -------------- 122 -------------- 138 --------------- 154 ---------------- 168 --------------- 186 -------------- 199 --------------- 213 -------------- 228 --------------- 244 -------------- 260 --------------- 277 -------------- 289 -------------- 299 --------------- 314 --------------- 329 -------------- 348 -------------- 365 --------------- 379 -------------- 396 -------------- 415 --------------- 428 ---------------- 440 --------------- 456 -------------- 475 -------------- 491 --------------- 505 -------------- 521 -------------- 535 --------------- 549 --------------- 561 -------------- 577 --------------- 592 --------------- 604 --------------- 616 --------------- 628 -------------- 641 --------------- 662 --------------- 679 --------------- 695 -------------- 706 --------------- 720 --------------- 736 -------------- 756 -------------- 771 --------------- 787 --------------- 803 --------------- 820 --------------- 836 -------------- 847 --------------- 860 --------------- 878 ---------------- 893 -------------- 908 --------------- 924 --------------- 937 -------------- 960 --------------- 975 ---------------- 990 --------------- 1005 ------------- 1018 ------------- 1032 ------------- 1050 -------------- 1063 ------------- 1084 -------------- 1101 ------------- 1120 -------------- 1133 --------------- 1148 -------------- 1160 ------------- 1177 ------------- 1192 -------------- 1212 -------------- 1227 -------------- 1241 -------------- 1260 ------------- 1275 -------------- 1289 ------------- 1305 -------------- 1320 -------------- 1334 -------------- 1348 --------------- 1361 ------------- 1377 -------------- 1393 -------------- 1405 -------------- 1421 ------------- 1436 ------------- 1450 -------------- 1466 ------------- 1478 -------------- 1492 -------------- 1507 -------------- 1525 -------------- 1541 -------------- 1555 -------------- 1568 -------------- 1586 -------------- 1599 -------------- 1614 -------------- 1630 -------------- 1647 --------------- 1666 -------------- 1683 -------------- 1696 -------------- 1713 -------------- 1724 -------------- 1739 -------------- 1753 -------------- 1773 --------------- 1787 ------------- 1802 -------------- 1823 ------------- 1839 -------------- 1851 -------------- 1865 ------------- 1879 -------------- 1891 ------------- 1903 -------------- 1917 ------------- 1930 -------------- 1945 ------------- 1960 -------------- 1976 -------------- 1992 ------------- 2010 -------------- 2023 -------------- 2038 ------------- 2054 --------------- 2067 --------------- 2080 --------------- 2095 -------------- 2113 -------------- 2128 ------------- 2144 -------------- 2159 -------------- 2173 ------------- 2189 --------------- 2199 -------------- 2214 -------------- 2230 -------------- 2243 --------------- 2257 --------------- 2271 -------------- 2288 ------------- 2302 -------------- 2316 --------------- 2331 -------------- 2345 -------------- 2363 -------------- 2381 -------------- 2396 ------------- 2409 --------------- 2427 -------------- 2441 -------------- 2453 ------------- 2469 -------------- 2480 ------------- 2495 --------------- 2508 -------------- 2524 ------------- 2536 -------------- 2553 -------------- 2570 ------------- 2583 -------------- 2598 -------------- 2612 -------------- 2626 -------------- 2638 -------------- 2653 -------------- 2671 -------------- 2686 -------------- 2700 -------------- 2717 --------------- 2734 -------------- 2751 -------------- 2770 -------------- 2782 --------------- 2795 -------------- 2812 ------------- 2828 --------------- 2839 --------------- 2851 -------------- 2868 --------------- 2881 -------------- 2894 --------------- 2908 -------------- 2921 --------------- 2935 -------------- 2950 -------------- 2962 -------------- 2975 --------------- 2989 --------------- 3000 -- │ histogram(2)= 0 2.1223 diff --git a/pkg/sql/opt/norm/testdata/rules/combo b/pkg/sql/opt/norm/testdata/rules/combo index 6185736cca60..8b83dc910d1d 100644 --- a/pkg/sql/opt/norm/testdata/rules/combo +++ b/pkg/sql/opt/norm/testdata/rules/combo @@ -117,7 +117,7 @@ SimplifyJoinFilters + └── i:2 = 9 [outer=(2), constraints=(/2: [/9 - /9]; tight), fd=()-->(2)] ================================================================================ PushFilterIntoJoinLeft - Cost: 2195.91 + Cost: 2195.92 ================================================================================ project ├── columns: s:4 @@ -226,7 +226,7 @@ PruneSelectCols └── k:1 = x:7 [outer=(1,7), constraints=(/1: (/NULL - ]; /7: (/NULL - ]), fd=(1)==(7), (7)==(1)] ================================================================================ EliminateProject - Cost: 2165.91 + Cost: 2165.92 ================================================================================ project ├── columns: s:4 @@ -264,7 +264,7 @@ EliminateProject └── k:1 = x:7 [outer=(1,7), constraints=(/1: (/NULL - ]; /7: (/NULL - ]), fd=(1)==(7), (7)==(1)] ================================================================================ PruneJoinRightCols - Cost: 2145.91 + Cost: 2145.92 ================================================================================ project ├── columns: s:4 diff --git a/pkg/sql/opt/norm/testdata/rules/scalar b/pkg/sql/opt/norm/testdata/rules/scalar index dbe4b2c3d918..9985de25c61a 100644 --- a/pkg/sql/opt/norm/testdata/rules/scalar +++ b/pkg/sql/opt/norm/testdata/rules/scalar @@ -925,16 +925,16 @@ SELECT k FROM e WHERE i IS NOT DISTINCT FROM NULL::FLOAT ---- project ├── columns: k:1(int!null) - ├── stats: [rows=10] - ├── cost: 14.52 + ├── stats: [rows=10.0000001] + ├── cost: 14.5200001 ├── key: (1) ├── prune: (1) ├── interesting orderings: (+1) └── scan t.public.e@secondary ├── columns: t.public.e.k:1(int!null) t.public.e.i:2(int) ├── constraint: /2/1: [/NULL - /NULL] - ├── stats: [rows=10, distinct(2)=1, null(2)=10] - ├── cost: 14.41 + ├── stats: [rows=10.0000001, distinct(2)=1, null(2)=10] + ├── cost: 14.4100001 ├── key: (1) ├── fd: ()-->(2) ├── prune: (1) diff --git a/pkg/sql/opt/partialidx/implicator_test.go b/pkg/sql/opt/partialidx/implicator_test.go index 529661a80fc2..71b08c481ee2 100644 --- a/pkg/sql/opt/partialidx/implicator_test.go +++ b/pkg/sql/opt/partialidx/implicator_test.go @@ -337,7 +337,7 @@ func makeFilters( Available: true, RowCount: 1000, ColStats: colStatsMap, - Selectivity: 1, + Selectivity: props.OneSelectivity, } // Create a fake Select and input so that normalization rules are run. diff --git a/pkg/sql/opt/props/histogram.go b/pkg/sql/opt/props/histogram.go index fcf6e8b2af0d..e97c5b247409 100644 --- a/pkg/sql/opt/props/histogram.go +++ b/pkg/sql/opt/props/histogram.go @@ -427,7 +427,7 @@ func (h *Histogram) addBucket(bucket *cat.HistogramBucket, desc bool) { // ApplySelectivity reduces the size of each histogram bucket according to // the given selectivity, and returns a new histogram with the results. -func (h *Histogram) ApplySelectivity(selectivity float64) *Histogram { +func (h *Histogram) ApplySelectivity(selectivity Selectivity) *Histogram { res := h.copy() for i := range res.buckets { b := &res.buckets[i] @@ -436,8 +436,8 @@ func (h *Histogram) ApplySelectivity(selectivity float64) *Histogram { n := b.NumRange d := b.DistinctRange - b.NumEq *= selectivity - b.NumRange *= selectivity + b.NumEq *= selectivity.AsFloat() + b.NumRange *= selectivity.AsFloat() if d == 0 { continue @@ -449,7 +449,7 @@ func (h *Histogram) ApplySelectivity(selectivity float64) *Histogram { // // This formula returns d * selectivity when d=n but is closer to d // when d << n. - b.DistinctRange = d - d*math.Pow(1-selectivity, n/d) + b.DistinctRange = d - d*math.Pow(1-selectivity.AsFloat(), n/d) } return res } @@ -614,11 +614,11 @@ func getFilteredBucket( // This span represents an equality condition with a value in the range // of this bucket. Use the distinct count of the bucket to estimate the // selectivity of the equality condition. - selectivity := 1.0 + selectivity := OneSelectivity if b.DistinctRange > 1 { - selectivity = 1 / b.DistinctRange + selectivity = MakeSelectivity(1 / b.DistinctRange) } - numEq = selectivity * b.NumRange + numEq = selectivity.AsFloat() * b.NumRange } else if ok && rangeBefore > 0 && isDiscrete(bucketLowerBound.ResolvedType()) { // If we were successful in finding the ranges before and after filtering // and the data type is discrete (e.g., integer, date, or timestamp), we diff --git a/pkg/sql/opt/props/selectivity.go b/pkg/sql/opt/props/selectivity.go new file mode 100644 index 000000000000..2cd11c241ac2 --- /dev/null +++ b/pkg/sql/opt/props/selectivity.go @@ -0,0 +1,84 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License included +// in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package props + +import "fmt" + +// epsilon is the minimum value Selectivity can hold, since it cannot be 0. +const epsilon = 1e-10 + +// Selectivity is a value is within the range of [epsilon, 1.0] representing +// the estimated fraction of rows that pass a given condition. +type Selectivity struct { + selectivity float64 +} + +// ZeroSelectivity is used in cases where selectivity is known to be zero. +var ZeroSelectivity = Selectivity{0} + +// OneSelectivity is used in cases where selectivity is known to be one. +var OneSelectivity = Selectivity{1.0} + +// MakeSelectivity initializes and validates a float64 to ensure it is in a +// valid range. This method is used for selectivity calculations involving +// other non-selectivity values. +func MakeSelectivity(sel float64) Selectivity { + return Selectivity{SelectivityInRange(sel)} +} + +// AsFloat returns the private selectivity field, allowing it to be accessed +// outside of this package. +func (s *Selectivity) AsFloat() float64 { + return s.selectivity +} + +// Multiply finds the product of two selectivities in the valid range and +// modifies the selectivity specified in the receiver to equal the product. +func (s *Selectivity) Multiply(other Selectivity) { + s.selectivity = SelectivityInRange(s.selectivity * other.selectivity) +} + +// Add finds the sum of two selectivities in the valid range and modifies +// the selectivity specified in the receiver to equal the sum. +func (s *Selectivity) Add(other Selectivity) { + s.selectivity = SelectivityInRange(s.selectivity + other.selectivity) +} + +// Divide finds the quotient of two selectivities in the valid range and +// modifies the selectivity specified in the receiver to equal the quotient. +func (s *Selectivity) Divide(other Selectivity) { + s.selectivity = SelectivityInRange(s.selectivity / other.selectivity) +} + +// MinSelectivity returns the smaller value of two selectivities +func MinSelectivity(a, b Selectivity) Selectivity { + if a.selectivity < b.selectivity { + return a + } + return b +} + +// SelectivityInRange performs the range check, if the selectivity falls +// outside of the range, this method will return the appropriate min/max value. +func SelectivityInRange(sel float64) float64 { + switch { + case sel < epsilon: + return epsilon + case sel > 1.0: + return 1.0 + default: + return sel + } +} + +func (s Selectivity) String() string { + return fmt.Sprintf("%f", s.selectivity) +} diff --git a/pkg/sql/opt/props/selectivity_test.go b/pkg/sql/opt/props/selectivity_test.go new file mode 100644 index 000000000000..5eebc4feb2ae --- /dev/null +++ b/pkg/sql/opt/props/selectivity_test.go @@ -0,0 +1,99 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License included +// in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package props + +import ( + "math" + "testing" +) + +func TestSelectivity(t *testing.T) { + test := func(actual, expected Selectivity) { + t.Helper() + if actual != expected { + t.Errorf("expected: %s, actual: %s", expected, actual) + } + } + + testFloat := func(actual, expected float64) { + t.Helper() + if actual != expected { + t.Errorf("expected: %f, actual: %f", expected, actual) + } + } + + testMultiply := func(actual, other, expected Selectivity) { + t.Helper() + actual.Multiply(other) + if actual != expected { + t.Errorf("expected: %s, actual: %s", expected, actual) + } + } + + testAdd := func(actual, other, expected Selectivity) { + t.Helper() + actual.Add(other) + if actual != expected { + t.Errorf("expected: %s, actual: %s", expected, actual) + } + } + + testDivide := func(actual, other, expected Selectivity) { + t.Helper() + actual.Divide(other) + if actual != expected { + t.Errorf("expected: %s, actual: %s", expected, actual) + } + } + + s := func(sel float64) Selectivity { + return MakeSelectivity(sel) + } + inf := math.MaxFloat64 + + // MinSelectivity variations. + test(MinSelectivity(s(0.4), s(0.5)), s(0.4)) + test(MinSelectivity(s(0.5), s(0.4)), s(0.4)) + test(MinSelectivity(ZeroSelectivity, OneSelectivity), ZeroSelectivity) + test(MinSelectivity(ZeroSelectivity, s(epsilon)), ZeroSelectivity) + test(MinSelectivity(s(0), s(epsilon)), s(epsilon)) + + // SelectivityInRange variations. + testFloat(SelectivityInRange(epsilon), epsilon) + testFloat(SelectivityInRange(1), 1) + testFloat(SelectivityInRange(0.5), 0.5) + testFloat(SelectivityInRange(1.3), 1) + testFloat(SelectivityInRange(0), epsilon) + testFloat(SelectivityInRange(1.3), 1) + testFloat(SelectivityInRange(inf), 1) + + // Multiply variations. + testMultiply(s(0), s(0), s(epsilon*epsilon)) + testMultiply(s(0.5), s(0.4), s(0.5*0.4)) + testMultiply(s(2), OneSelectivity, OneSelectivity) + testMultiply(s(inf), s(inf), OneSelectivity) + testMultiply(s(0), s(0.4), s(epsilon*0.4)) + testMultiply(ZeroSelectivity, s(0.5), s(epsilon)) + + // Add variations. + testAdd(s(0), s(0), s(epsilon+epsilon)) + testAdd(s(0.5), s(0.4), s(0.5+0.4)) + testAdd(s(0.5), s(0.6), OneSelectivity) + testAdd(s(inf), s(inf), OneSelectivity) + testAdd(OneSelectivity, OneSelectivity, OneSelectivity) + testAdd(ZeroSelectivity, ZeroSelectivity, s(epsilon)) + + // Divide variations. + testDivide(s(0.4), s(0.5), s(0.8)) + testDivide(s(0.5), OneSelectivity, s(0.5)) + testDivide(OneSelectivity, s(0.5), OneSelectivity) + testDivide(OneSelectivity, OneSelectivity, OneSelectivity) +} diff --git a/pkg/sql/opt/props/statistics.go b/pkg/sql/opt/props/statistics.go index 5fe4129d7d8c..ae8aa8a5e271 100644 --- a/pkg/sql/opt/props/statistics.go +++ b/pkg/sql/opt/props/statistics.go @@ -63,7 +63,7 @@ type Statistics struct { // Selectivity is a value between 0 and 1 representing the estimated // reduction in number of rows for the top-level operator in this // expression. - Selectivity float64 + Selectivity Selectivity } // Init initializes the data members of Statistics. @@ -73,11 +73,11 @@ func (s *Statistics) Init(relProps *Relational) (zeroCardinality bool) { *s = Statistics{} if relProps.Cardinality.IsZero() { s.RowCount = 0 - s.Selectivity = 0 + s.Selectivity = ZeroSelectivity s.Available = true return true } - s.Selectivity = 1 + s.Selectivity = OneSelectivity return false } @@ -94,9 +94,17 @@ func (s *Statistics) CopyFrom(other *Statistics) { // Histograms are not updated. // See ColumnStatistic.ApplySelectivity for updating distinct counts, null // counts, and histograms. -func (s *Statistics) ApplySelectivity(selectivity float64) { - s.RowCount *= selectivity - s.Selectivity *= selectivity +func (s *Statistics) ApplySelectivity(selectivity Selectivity) { + s.RowCount *= selectivity.AsFloat() + s.Selectivity.Multiply(selectivity) +} + +// UnapplySelectivity divides by a given selectivity to the statistics. +// RowCount and Selectivity are updated. Note that DistinctCounts, NullCounts, +// and Histograms are not updated. +func (s *Statistics) UnapplySelectivity(selectivity Selectivity) { + s.RowCount /= selectivity.AsFloat() + s.Selectivity.Divide(selectivity) } // UnionWith unions this Statistics object with another Statistics object. It @@ -106,7 +114,7 @@ func (s *Statistics) ApplySelectivity(selectivity float64) { func (s *Statistics) UnionWith(other *Statistics) { s.Available = s.Available && other.Available s.RowCount += other.RowCount - s.Selectivity += other.Selectivity + s.Selectivity.Add(other.Selectivity) } func (s *Statistics) String() string { @@ -170,19 +178,19 @@ type ColumnStatistic struct { // ApplySelectivity updates the distinct count, null count, and histogram // according to a given selectivity. -func (c *ColumnStatistic) ApplySelectivity(selectivity, inputRows float64) { +func (c *ColumnStatistic) ApplySelectivity(selectivity Selectivity, inputRows float64) { // Since the null count is a simple count of all null rows, we can // just multiply the selectivity with it. - c.NullCount *= selectivity + c.NullCount *= selectivity.AsFloat() if c.Histogram != nil { c.Histogram = c.Histogram.ApplySelectivity(selectivity) } - if selectivity == 1 || c.DistinctCount == 0 { + if selectivity == OneSelectivity || c.DistinctCount == 0 { return } - if selectivity == 0 { + if selectivity == ZeroSelectivity { c.DistinctCount = 0 return } @@ -197,7 +205,7 @@ func (c *ColumnStatistic) ApplySelectivity(selectivity, inputRows float64) { // // This formula returns d * selectivity when d=n but is closer to d // when d << n. - c.DistinctCount = d - d*math.Pow(1-selectivity, n/d) + c.DistinctCount = d - d*math.Pow(1-selectivity.AsFloat(), n/d) const epsilon = 1e-10 if c.DistinctCount < epsilon { // Avoid setting the distinct count to 0 (since the row count is diff --git a/pkg/sql/opt/xform/testdata/coster/join b/pkg/sql/opt/xform/testdata/coster/join index 36e2626c45ea..d74ce7df2b6d 100644 --- a/pkg/sql/opt/xform/testdata/coster/join +++ b/pkg/sql/opt/xform/testdata/coster/join @@ -400,15 +400,15 @@ SELECT * FROM abc WHERE c = 1 ---- index-join abc ├── columns: a:1!null b:2 c:3!null - ├── stats: [rows=9.9000002, distinct(3)=1, null(3)=0] - ├── cost: 74.2110014 + ├── stats: [rows=9.9005002, distinct(3)=1, null(3)=0] + ├── cost: 74.2145464 ├── key: (1) ├── fd: ()-->(3), (1)-->(2) └── scan abc@c_idx ├── columns: a:1!null c:3!null ├── constraint: /3/1: [/1 - /1] - ├── stats: [rows=9.9000002, distinct(3)=1, null(3)=0] - ├── cost: 14.3060002 + ├── stats: [rows=9.9005002, distinct(3)=1, null(3)=0] + ├── cost: 14.3065202 ├── key: (1) └── fd: ()-->(3) @@ -601,18 +601,18 @@ WHERE w = 'foo' AND x = '2AB23800-06B1-4E19-A3BB-DF3768B808D2' AND (i,j,k,l,m,n) ---- project ├── columns: w:1!null x:2!null y:3!null z:4!null - ├── stats: [rows=4.50439883] + ├── stats: [rows=4.50439933] ├── cost: 12231.6 ├── fd: ()-->(1,2) └── inner-join (lookup abcde@idx_abcd) ├── columns: w:1!null x:2!null y:3!null z:4!null i:5!null j:6!null k:7!null l:8!null m:9!null n:10!null a:13!null b:14!null c:15!null ├── key columns: [1 2 3] = [13 14 15] - ├── stats: [rows=4.50439883, distinct(1)=0.9, null(1)=0, distinct(2)=0.9, null(2)=0, distinct(3)=0.884031733, null(3)=0, distinct(13)=0.9, null(13)=0, distinct(14)=0.9, null(14)=0, distinct(15)=0.884031733, null(15)=0] + ├── stats: [rows=4.50439933, distinct(1)=0.9000001, null(1)=0, distinct(2)=0.9000001, null(2)=0, distinct(3)=0.88403183, null(3)=0, distinct(13)=0.9000001, null(13)=0, distinct(14)=0.9000001, null(14)=0, distinct(15)=0.88403183, null(15)=0] ├── cost: 12231.545 ├── fd: ()-->(1,2,5-10,13,14), (1)==(13), (13)==(1), (2)==(14), (14)==(2), (3)==(15), (15)==(3) ├── select │ ├── columns: w:1!null x:2!null y:3!null z:4!null i:5!null j:6!null k:7!null l:8!null m:9!null n:10!null - │ ├── stats: [rows=0.9, distinct(1)=0.9, null(1)=0, distinct(2)=0.9, null(2)=0, distinct(3)=0.884031733, null(3)=0, distinct(4)=0.899635587, null(4)=0, distinct(5)=0.9, null(5)=0, distinct(6)=0.9, null(6)=0, distinct(7)=0.9, null(7)=0, distinct(8)=0.9, null(8)=0, distinct(9)=0.9, null(9)=0, distinct(10)=0.9, null(10)=0, distinct(5-10)=0.9, null(5-10)=0] + │ ├── stats: [rows=0.9000001, distinct(1)=0.9000001, null(1)=0, distinct(2)=0.9000001, null(2)=0, distinct(3)=0.88403183, null(3)=0, distinct(4)=0.899635687, null(4)=0, distinct(5)=0.9000001, null(5)=0, distinct(6)=0.9000001, null(6)=0, distinct(7)=0.9000001, null(7)=0, distinct(8)=0.9000001, null(8)=0, distinct(9)=0.9000001, null(9)=0, distinct(10)=0.9000001, null(10)=0, distinct(5-10)=0.9000001, null(5-10)=0] │ ├── cost: 12204.11 │ ├── fd: ()-->(1,2,5-10) │ ├── scan wxyzijklmn diff --git a/pkg/sql/opt/xform/testdata/external/planet-osm b/pkg/sql/opt/xform/testdata/external/planet-osm index 538d24a2aac3..375a8fdae0e5 100644 --- a/pkg/sql/opt/xform/testdata/external/planet-osm +++ b/pkg/sql/opt/xform/testdata/external/planet-osm @@ -1727,7 +1727,7 @@ ORDER BY sort ├── columns: way:69!null int_tc_type:99!null ├── immutable - ├── stats: [rows=2632.05556, distinct(69)=2632.05556, null(69)=0] + ├── stats: [rows=2632.05557, distinct(69)=2632.05557, null(69)=0] ├── key: (69) ├── fd: (69)-->(99) ├── ordering: +69 @@ -1736,36 +1736,36 @@ sort ├── grouping columns: p.way:69!null ├── internal-ordering: +146 opt(29,69) ├── immutable - ├── stats: [rows=2632.05556, distinct(69)=2632.05556, null(69)=0] + ├── stats: [rows=2632.05557, distinct(69)=2632.05557, null(69)=0] ├── key: (69) ├── fd: (69)-->(99) ├── sort │ ├── columns: p.highway:29!null p.way:69!null l.highway:99!null l.way:141!null column1:145!null column2:146!null │ ├── immutable - │ ├── stats: [rows=386640.471, distinct(69)=2632.05556, null(69)=0, distinct(99)=5, null(99)=0, distinct(145)=5, null(145)=0] + │ ├── stats: [rows=386640.472, distinct(69)=2632.05557, null(69)=0, distinct(99)=5, null(99)=0, distinct(145)=5, null(145)=0] │ ├── fd: ()-->(29), (99)==(145), (145)==(99) │ ├── ordering: +146 opt(29,69) [actual: +146] │ └── inner-join (hash) │ ├── columns: p.highway:29!null p.way:69!null l.highway:99!null l.way:141!null column1:145!null column2:146!null │ ├── immutable - │ ├── stats: [rows=386640.471, distinct(69)=2632.05556, null(69)=0, distinct(99)=5, null(99)=0, distinct(145)=5, null(145)=0] + │ ├── stats: [rows=386640.472, distinct(69)=2632.05557, null(69)=0, distinct(99)=5, null(99)=0, distinct(145)=5, null(145)=0] │ ├── fd: ()-->(29), (99)==(145), (145)==(99) │ ├── inner-join (lookup planet_osm_line [as=l]) │ │ ├── columns: p.highway:29!null p.way:69!null l.highway:99 l.way:141!null │ │ ├── key columns: [142] = [142] │ │ ├── lookup columns are key │ │ ├── immutable - │ │ ├── stats: [rows=3926737.36, distinct(29)=1, null(29)=0, distinct(69)=2632.05556, null(69)=0, distinct(99)=31, null(99)=1529566.44, distinct(141)=146376, null(141)=0] + │ │ ├── stats: [rows=3926737.38, distinct(29)=1, null(29)=0, distinct(69)=2632.05557, null(69)=0, distinct(99)=31, null(99)=1529566.45, distinct(141)=146376, null(141)=0] │ │ ├── fd: ()-->(29) │ │ ├── inner-join (inverted planet_osm_line@planet_osm_line_way_idx [as=l]) │ │ │ ├── columns: p.highway:29!null p.way:69 l.rowid:142!null │ │ │ ├── inverted-expr │ │ │ │ └── st_dwithin(p.way:69, l.way:141, 100.0) - │ │ │ ├── stats: [rows=3926737.36, distinct(29)=1, null(29)=0] + │ │ │ ├── stats: [rows=3926737.38, distinct(29)=1, null(29)=0] │ │ │ ├── fd: ()-->(29) │ │ │ ├── select │ │ │ │ ├── columns: p.highway:29!null p.way:69 - │ │ │ │ ├── stats: [rows=2632.05556, distinct(29)=1, null(29)=0, distinct(69)=2632.05556, null(69)=0] + │ │ │ │ ├── stats: [rows=2632.05557, distinct(29)=1, null(29)=0, distinct(69)=2632.05557, null(69)=0] │ │ │ │ ├── fd: ()-->(29) │ │ │ │ ├── scan planet_osm_point [as=p] │ │ │ │ │ ├── columns: p.highway:29 p.way:69 diff --git a/pkg/sql/opt/xform/testdata/external/trading b/pkg/sql/opt/xform/testdata/external/trading index a9d219550f2a..ff69db46470a 100644 --- a/pkg/sql/opt/xform/testdata/external/trading +++ b/pkg/sql/opt/xform/testdata/external/trading @@ -572,7 +572,7 @@ project │ └── scan cardsinfo@cardsinfoversionindex │ ├── columns: dealerid:8!null cardid:9!null version:16!null │ ├── constraint: /8/16: (/1/1584421773604892000.0000000000 - /1] - │ ├── stats: [rows=0.0201621426, distinct(8)=0.0201621426, null(8)=0, distinct(9)=0.0201621393, null(9)=0, distinct(16)=0.0201621426, null(16)=0, distinct(8,16)=0.0201621426, null(8,16)=0] + │ ├── stats: [rows=0.0201621426, distinct(8)=0.0201621426, null(8)=0, distinct(9)=0.0201621426, null(9)=0, distinct(16)=0.0201621426, null(16)=0, distinct(8,16)=0.0201621426, null(8,16)=0] │ │ histogram(16)= 0 0 0.020162 0 │ │ <--- 1584421773604892000.0000000000 ---------- 1584421778604892000 │ ├── key: (9)