Skip to content

Commit a205c4c

Browse files
committed
draft
1 parent 640db09 commit a205c4c

File tree

2 files changed

+53
-32
lines changed

2 files changed

+53
-32
lines changed

pkg/sql/opt/memo/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ go_library(
4747
"//pkg/sql/sem/tree",
4848
"//pkg/sql/sem/tree/treewindow",
4949
"//pkg/sql/sem/volatility",
50+
"//pkg/sql/sessiondata",
5051
"//pkg/sql/stats",
5152
"//pkg/sql/types",
5253
"//pkg/util/buildutil",

pkg/sql/opt/memo/statistics_builder.go

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/cockroachdb/cockroach/pkg/sql/sem/eval"
2222
"github.com/cockroachdb/cockroach/pkg/sql/sem/idxtype"
2323
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
24+
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
2425
"github.com/cockroachdb/cockroach/pkg/sql/stats"
2526
"github.com/cockroachdb/cockroach/pkg/sql/types"
2627
"github.com/cockroachdb/cockroach/pkg/util/buildutil"
@@ -649,6 +650,32 @@ func GetTableStats(md *opt.Metadata, tabID opt.TableID) (*props.Statistics, bool
649650
return stats, ok
650651
}
651652

653+
func isEligibleFullStats(
654+
stat cat.TableStatistic, sd *sessiondata.SessionData, asOf hlc.Timestamp,
655+
) bool {
656+
createdAtTS := hlc.Timestamp{WallTime: stat.CreatedAt().UnixNano()}
657+
if stat.IsPartial() ||
658+
stat.IsMerged() && !sd.OptimizerUseMergedPartialStatistics ||
659+
stat.IsForecast() && !sd.OptimizerUseForecasts || createdAtTS.After(asOf) {
660+
return false
661+
}
662+
return true
663+
}
664+
665+
// getNextFullStats returns the index of the next eligible full statistics.
666+
func getNextFullStats(
667+
start int, tab cat.Table, sd *sessiondata.SessionData, asOf hlc.Timestamp,
668+
) int {
669+
for i := start; i < tab.StatisticCount(); i++ {
670+
stat := tab.Statistic(i)
671+
if !isEligibleFullStats(stat, sd, asOf) {
672+
continue
673+
}
674+
return i
675+
}
676+
return -1
677+
}
678+
652679
// makeTableStatistics returns the available statistics for the given table.
653680
// Statistics are derived lazily and are cached in the metadata, since they may
654681
// be accessed multiple times during query optimization. For more details, see
@@ -698,31 +725,30 @@ func (sb *statisticsBuilder) makeTableStatistics(tabID opt.TableID) *props.Stati
698725
var first int
699726
sd := sb.evalCtx.SessionData()
700727
for first < tab.StatisticCount() {
701-
stat := tab.Statistic(first)
702-
createdAtTS := hlc.Timestamp{WallTime: stat.CreatedAt().UnixNano()}
703-
if stat.IsPartial() ||
704-
stat.IsMerged() && !sd.OptimizerUseMergedPartialStatistics ||
705-
stat.IsForecast() && !sd.OptimizerUseForecasts {
706-
first++
707-
continue
708-
} else if createdAtTS.After(asOfTs) {
709-
// The stats is too new, skip it.
710-
first++
711-
continue
712-
} else if statsCanaryWindow > 0 && !useCanary && first < tab.StatisticCount()-1 {
713-
// The following, we are getting full statistics for the stable stats,
714-
// in contrast to the canary stats. The canary stats is skipped.
715-
// If there remains only one full statistics, don't skip.
716-
if stat.CreatedAt() == skippedStatsCreationTimestamp && !skippedStatsCreationTimestamp.IsZero() {
717-
// We've already seen this canary stat, so skip it.
718-
first++
719-
continue
720-
}
721-
// Found a canary stats (defined as creation time within the canary window size). Register the
722-
// creation timestamp and move on the next older one.
723-
if createdAtTS.AddDuration(statsCanaryWindow).After(asOfTs) {
728+
first = getNextFullStats(first, tab, sd, asOfTs)
729+
if first < 0 {
730+
break
731+
}
732+
if statsCanaryWindow > 0 && !useCanary {
733+
// We should use stable stats, which is defined as the second most recent full stats.
734+
stat := tab.Statistic(first)
735+
createdAtTS := hlc.Timestamp{WallTime: stat.CreatedAt().UnixNano()}
736+
// Check if the current full stats is the last available one. If yes,
737+
// use it as both canary and stable stats.
738+
nextFullStatsIdx := getNextFullStats(first+1, tab, sd, asOfTs)
739+
if nextFullStatsIdx != -1 {
740+
// The following, we are getting full statistics for the stable stats,
741+
// in contrast to the canary stats. The canary stats is skipped.
742+
// If there remains only one full statistics, don't skip.
743+
if stat.CreatedAt() == skippedStatsCreationTimestamp && !skippedStatsCreationTimestamp.IsZero() {
744+
// We've already seen this canary stat, so skip it.
745+
first++
746+
continue
747+
}
748+
// Found a canary stats (defined as creation time within the canary window size). Register the
749+
// creation timestamp and move on the next older one.
724750
// If there is already a canary stats skipped, we don't skip again.
725-
if skippedStatsCreationTimestamp.IsZero() {
751+
if createdAtTS.AddDuration(statsCanaryWindow).After(asOfTs) && skippedStatsCreationTimestamp.IsZero() {
726752
skippedStatsCreationTimestamp = stat.CreatedAt()
727753
first++
728754
continue
@@ -732,7 +758,7 @@ func (sb *statisticsBuilder) makeTableStatistics(tabID opt.TableID) *props.Stati
732758
break
733759
}
734760

735-
if first >= tab.StatisticCount() {
761+
if first >= tab.StatisticCount() || first < 0 {
736762
// No statistics.
737763
stats.Available = false
738764
stats.RowCount = unknownRowCount
@@ -750,13 +776,7 @@ func (sb *statisticsBuilder) makeTableStatistics(tabID opt.TableID) *props.Stati
750776
EachStat:
751777
for i := first; i < tab.StatisticCount(); i++ {
752778
stat := tab.Statistic(i)
753-
if stat.IsPartial() {
754-
continue
755-
}
756-
if stat.IsMerged() && !sb.evalCtx.SessionData().OptimizerUseMergedPartialStatistics {
757-
continue
758-
}
759-
if stat.IsForecast() && !sb.evalCtx.SessionData().OptimizerUseForecasts {
779+
if !isEligibleFullStats(stat, sd, asOfTs) {
760780
continue
761781
}
762782
if stat.ColumnCount() > 1 && !sb.evalCtx.SessionData().OptimizerUseMultiColStats {

0 commit comments

Comments
 (0)