diff --git a/pkg/ccl/multiregionccl/multiregion_system_table_test.go b/pkg/ccl/multiregionccl/multiregion_system_table_test.go index 4718917c4295..7fd74f5e4ef2 100644 --- a/pkg/ccl/multiregionccl/multiregion_system_table_test.go +++ b/pkg/ccl/multiregionccl/multiregion_system_table_test.go @@ -87,6 +87,7 @@ func TestMrSystemDatabase(t *testing.T) { sDB := sqlutils.MakeSQLRunner(systemSQL) + sDB.Exec(t, `ANALYZE system.sqlliveness;`) sDB.Exec(t, `SET CLUSTER SETTING sql.multiregion.system_database_multiregion.enabled = true`) sDB.Exec(t, `ALTER DATABASE system SET PRIMARY REGION "us-east1"`) sDB.Exec(t, `ALTER DATABASE system ADD REGION "us-east2"`) diff --git a/pkg/sql/region_util.go b/pkg/sql/region_util.go index 1df7930e6d5f..6d3990a6eaae 100644 --- a/pkg/sql/region_util.go +++ b/pkg/sql/region_util.go @@ -2521,6 +2521,10 @@ func (p *planner) setSystemDatabaseSurvival(ctx context.Context) error { return nil } +// systemTableLocalityChangeJobName is the job name used when the locality is converted +// to regional by row. +const systemTableLocalityChangeJobName = "convert system.%s to %s locality" + // optimizeSystemDatabase configures some tables in the system data as // global and regional by row. The locality changes reduce how long it // takes a server to start up in a multi-region deployment. @@ -2604,7 +2608,7 @@ func (p *planner) optimizeSystemDatabase(ctx context.Context) error { return err } - jobName := fmt.Sprintf("convert system.%s to %s locality", desc.GetName(), locality) + jobName := fmt.Sprintf(systemTableLocalityChangeJobName, desc.GetName(), locality) return p.writeSchemaChange(ctx, desc, descpb.InvalidMutationID, jobName) } diff --git a/pkg/sql/schema_changer.go b/pkg/sql/schema_changer.go index 28c0f0d79a29..58c07f1429aa 100644 --- a/pkg/sql/schema_changer.go +++ b/pkg/sql/schema_changer.go @@ -920,7 +920,18 @@ func (sc *SchemaChanger) exec(ctx context.Context) error { if sc.mutationID == descpb.InvalidMutationID { // Nothing more to do. isCreateTableAs := tableDesc.Adding() && tableDesc.IsAs() - return waitToUpdateLeases(isCreateTableAs /* refreshStats */) + // If we are converting a system database table to MR, we should force + // a stats refresh so that the stats also have the correct type. There is + // a potential race condition between waiting for leases and deleting the + // statistics using optimizeDatabase, where between those two point statistics + // with the wrong type could show up. To minimize any transient condition, + // lets force a refresh of stats here. + isSystemDatabaseTransformation := tableDesc.GetParentID() == keys.SystemDatabaseID && + (strings.HasPrefix(sc.job.Payload().Description, + fmt.Sprintf(systemTableLocalityChangeJobName, tableDesc.GetName(), "regional by row")) || + strings.HasPrefix(sc.job.Payload().Description, + fmt.Sprintf(systemTableLocalityChangeJobName, tableDesc.GetName(), "global"))) + return waitToUpdateLeases(isCreateTableAs || isSystemDatabaseTransformation /* refreshStats */) } if err := sc.initJobRunningStatus(ctx); err != nil {