@@ -410,34 +410,24 @@ func (b *Builder) maybeAnnotateWithEstimates(node exec.Node, e memo.RelExpr) {
410410 }
411411 if scan , ok := e .(* memo.ScanExpr ); ok {
412412 tab := b .mem .Metadata ().Table (scan .Table )
413- if tab .StatisticCount () > 0 {
414- // The first stat is the most recent full one.
415- var first int
416- for first < tab .StatisticCount () &&
417- (tab .Statistic (first ).IsPartial () ||
418- (tab .Statistic (first ).IsMerged () && ! b .evalCtx .SessionData ().OptimizerUseMergedPartialStatistics ) ||
419- (tab .Statistic (first ).IsForecast () && ! b .evalCtx .SessionData ().OptimizerUseForecasts )) {
420- first ++
413+ first := cat .FindLatestFullStat (tab , b .evalCtx .SessionData ())
414+ if first < tab .StatisticCount () {
415+ stat := tab .Statistic (first )
416+ val .TableStatsRowCount = stat .RowCount ()
417+ if val .TableStatsRowCount == 0 {
418+ val .TableStatsRowCount = 1
421419 }
422-
423- if first < tab .StatisticCount () {
424- stat := tab .Statistic (first )
425- val .TableStatsRowCount = stat .RowCount ()
426- if val .TableStatsRowCount == 0 {
427- val .TableStatsRowCount = 1
428- }
429- val .TableStatsCreatedAt = stat .CreatedAt ()
430- val .LimitHint = scan .RequiredPhysical ().LimitHint
431- val .Forecast = stat .IsForecast ()
432- if val .Forecast {
433- val .ForecastAt = stat .CreatedAt ()
434- // Find the first non-forecast full stat.
435- for i := first + 1 ; i < tab .StatisticCount (); i ++ {
436- nextStat := tab .Statistic (i )
437- if ! nextStat .IsPartial () && ! nextStat .IsForecast () {
438- val .TableStatsCreatedAt = nextStat .CreatedAt ()
439- break
440- }
420+ val .TableStatsCreatedAt = stat .CreatedAt ()
421+ val .LimitHint = scan .RequiredPhysical ().LimitHint
422+ val .Forecast = stat .IsForecast ()
423+ if val .Forecast {
424+ val .ForecastAt = stat .CreatedAt ()
425+ // Find the first non-forecast full stat.
426+ for i := first + 1 ; i < tab .StatisticCount (); i ++ {
427+ nextStat := tab .Statistic (i )
428+ if ! nextStat .IsPartial () && ! nextStat .IsForecast () {
429+ val .TableStatsCreatedAt = nextStat .CreatedAt ()
430+ break
441431 }
442432 }
443433 }
@@ -898,26 +888,23 @@ func (b *Builder) buildScan(scan *memo.ScanExpr) (_ execPlan, outputCols colOrdM
898888 b .TotalScanRows += stats .RowCount
899889 b .ScanCounts [exec .ScanWithStatsCount ]++
900890
901- // The first stat is the most recent full one. Check if it was a forecast.
902- var first int
903- for first < tab .StatisticCount () && tab .Statistic (first ).IsPartial () {
904- first ++
905- }
891+ sd := b .evalCtx .SessionData ()
892+ first := cat .FindLatestFullStat (tab , sd )
906893 if first < tab .StatisticCount () && tab .Statistic (first ).IsForecast () {
907- if b .evalCtx .SessionData ().OptimizerUseForecasts {
908- b .ScanCounts [exec .ScanWithStatsForecastCount ]++
894+ b .ScanCounts [exec .ScanWithStatsForecastCount ]++
909895
910- // Calculate time since the forecast (or negative time until the forecast).
911- nanosSinceStatsForecasted := timeutil .Since (tab .Statistic (first ).CreatedAt ())
912- if nanosSinceStatsForecasted .Abs () > b .NanosSinceStatsForecasted .Abs () {
913- b .NanosSinceStatsForecasted = nanosSinceStatsForecasted
914- }
915- }
916- // Find the first non-forecast full stat.
917- for first < tab .StatisticCount () &&
918- (tab .Statistic (first ).IsPartial () || tab .Statistic (first ).IsForecast ()) {
919- first ++
896+ // Calculate time since the forecast (or negative time until the forecast).
897+ nanosSinceStatsForecasted := timeutil .Since (tab .Statistic (first ).CreatedAt ())
898+ if nanosSinceStatsForecasted .Abs () > b .NanosSinceStatsForecasted .Abs () {
899+ b .NanosSinceStatsForecasted = nanosSinceStatsForecasted
920900 }
901+
902+ // Since currently 'first' points at the forecast, then usage of the
903+ // forecasts must be enabled, so in order to find the first full
904+ // non-forecast stat, we'll temporarily disable their usage.
905+ sd .OptimizerUseForecasts = false
906+ first = cat .FindLatestFullStat (tab , sd )
907+ sd .OptimizerUseForecasts = true
921908 }
922909
923910 if first < tab .StatisticCount () {
@@ -945,8 +932,9 @@ func (b *Builder) buildScan(scan *memo.ScanExpr) (_ execPlan, outputCols colOrdM
945932 }
946933
947934 var params exec.ScanParams
948- params , outputCols , err = b .scanParams (tab , & scan .ScanPrivate ,
949- scan .Relational (), scan .RequiredPhysical (), statsCreatedAt )
935+ params , outputCols , err = b .scanParams (
936+ tab , & scan .ScanPrivate , scan .Relational (), scan .RequiredPhysical (), statsCreatedAt ,
937+ )
950938 if err != nil {
951939 return execPlan {}, colOrdMap {}, err
952940 }
0 commit comments