@@ -38,6 +38,7 @@ import (
3838 "github.com/cockroachdb/cockroach/pkg/util/hlc"
3939 "github.com/cockroachdb/cockroach/pkg/util/log"
4040 "github.com/cockroachdb/cockroach/pkg/util/log/eventpb"
41+ "github.com/cockroachdb/cockroach/pkg/util/protoutil"
4142 "github.com/cockroachdb/errors"
4243 "github.com/cockroachdb/redact"
4344)
@@ -77,7 +78,7 @@ func StubTableStats(
7778) ([]* stats.TableStatisticProto , error ) {
7879 colStats , err := createStatsDefaultColumns (
7980 context .Background (), desc , false /* virtColEnabled */ , false , /* multiColEnabled */
80- nonIndexColHistogramBuckets , nil , /* evalCtx */
81+ false /* partialStats */ , nonIndexColHistogramBuckets , nil , /* evalCtx */
8182 )
8283 if err != nil {
8384 return nil , err
@@ -249,7 +250,13 @@ func (n *createStatsNode) makeJobRecord(ctx context.Context) (*jobs.Record, erro
249250 }
250251 defaultHistogramBuckets := stats .GetDefaultHistogramBuckets (n .p .ExecCfg ().SV (), tableDesc )
251252 if colStats , err = createStatsDefaultColumns (
252- ctx , tableDesc , virtColEnabled , multiColEnabled , defaultHistogramBuckets , n .p .EvalContext (),
253+ ctx ,
254+ tableDesc ,
255+ virtColEnabled ,
256+ multiColEnabled ,
257+ n .Options .UsingExtremes ,
258+ defaultHistogramBuckets ,
259+ n .p .EvalContext (),
253260 ); err != nil {
254261 return nil , err
255262 }
@@ -366,13 +373,17 @@ const maxNonIndexCols = 100
366373// predicate expressions are also likely to appear in query filters, so stats
367374// are collected for those columns as well.
368375//
376+ // If partialStats is true, we only collect statistics on single columns that
377+ // are prefixes of forwards indexes. Partial statistic creation only supports
378+ // these columns.
379+ //
369380// In addition to the index columns, we collect stats on up to maxNonIndexCols
370381// other columns from the table. We only collect histograms for index columns,
371382// plus any other boolean or enum columns (where the "histogram" is tiny).
372383func createStatsDefaultColumns (
373384 ctx context.Context ,
374385 desc catalog.TableDescriptor ,
375- virtColEnabled , multiColEnabled bool ,
386+ virtColEnabled , multiColEnabled , partialStats bool ,
376387 defaultHistogramBuckets uint32 ,
377388 evalCtx * eval.Context ,
378389) ([]jobspb.CreateStatsDetails_ColStat , error ) {
@@ -472,6 +483,23 @@ func createStatsDefaultColumns(
472483 return nil
473484 }
474485
486+ // Only collect statistics on single columns that are prefixes of forward
487+ // indexes for partial statistics.
488+ if partialStats {
489+ for _ , idx := range desc .ActiveIndexes () {
490+ if idx .GetType () != descpb .IndexDescriptor_FORWARD || idx .IsPartial () {
491+ continue
492+ }
493+ if idx .NumKeyColumns () != 0 {
494+ colID := idx .GetKeyColumnID (0 )
495+ if err := addIndexColumnStatsIfNotExists (colID , false /* isInverted */ ); err != nil {
496+ return nil , err
497+ }
498+ }
499+ }
500+ return colStats , nil
501+ }
502+
475503 // Add column stats for the primary key.
476504 primaryIdx := desc .GetPrimaryIndex ()
477505 for i := 0 ; i < primaryIdx .NumKeyColumns (); i ++ {
@@ -690,13 +718,33 @@ func (r *createStatsResumer) Resume(ctx context.Context, execCtx interface{}) er
690718 }
691719
692720 dsp := innerP .DistSQLPlanner ()
693- planCtx := dsp .NewPlanningCtx (ctx , innerEvalCtx , innerP , txn .KV (), FullDistribution )
694721 // CREATE STATS flow doesn't produce any rows and only emits the
695722 // metadata, so we can use a nil rowContainerHelper.
696723 resultWriter := NewRowResultWriter (nil /* rowContainer */ )
697- if err := dsp .planAndRunCreateStats (
698- ctx , innerEvalCtx , planCtx , innerP .SemaCtx (), txn .KV (), r .job , resultWriter ,
699- ); err != nil {
724+
725+ var err error
726+ if details .UsingExtremes {
727+ for _ , colStat := range details .ColumnStats {
728+ // Plan and run partial stats on multiple columns separately since each
729+ // partial stat collection will use a different index and have different
730+ // plans.
731+ singleColDetails := protoutil .Clone (& details ).(* jobspb.CreateStatsDetails )
732+ singleColDetails .ColumnStats = []jobspb.CreateStatsDetails_ColStat {colStat }
733+ planCtx := dsp .NewPlanningCtx (ctx , innerEvalCtx , innerP , txn .KV (), FullDistribution )
734+ if err = dsp .planAndRunCreateStats (
735+ ctx , innerEvalCtx , planCtx , innerP .SemaCtx (), txn .KV (), resultWriter , r .job .ID (), * singleColDetails ,
736+ ); err != nil {
737+ break
738+ }
739+ }
740+ } else {
741+ planCtx := dsp .NewPlanningCtx (ctx , innerEvalCtx , innerP , txn .KV (), FullDistribution )
742+ err = dsp .planAndRunCreateStats (
743+ ctx , innerEvalCtx , planCtx , innerP .SemaCtx (), txn .KV (), resultWriter , r .job .ID (), details ,
744+ )
745+ }
746+
747+ if err != nil {
700748 // Check if this was a context canceled error and restart if it was.
701749 if grpcutil .IsContextCanceled (err ) {
702750 return jobs .MarkAsRetryJobError (err )
0 commit comments