diff --git a/docs/generated/metrics/metrics.html b/docs/generated/metrics/metrics.html
index 89ab705bafac..9c347f34d101 100644
--- a/docs/generated/metrics/metrics.html
+++ b/docs/generated/metrics/metrics.html
@@ -1570,6 +1570,7 @@
APPLICATION | sql.savepoint.started.count | Number of SQL SAVEPOINT statements started | SQL Statements | COUNTER | COUNT | AVG | NON_NEGATIVE_DERIVATIVE |
APPLICATION | sql.savepoint.started.count.internal | Number of SQL SAVEPOINT statements started (internal queries) | SQL Internal Statements | COUNTER | COUNT | AVG | NON_NEGATIVE_DERIVATIVE |
APPLICATION | sql.schema.invalid_objects | Gauge of detected invalid objects within the system.descriptor table (measured by querying crdb_internal.invalid_objects) | Objects | GAUGE | COUNT | AVG | NONE |
+APPLICATION | sql.schema_changer.object_count | Counter of the number of objects in the cluster | Objects | GAUGE | COUNT | AVG | NONE |
APPLICATION | sql.schema_changer.permanent_errors | Counter of the number of permanent errors experienced by the schema changer | Errors | COUNTER | COUNT | AVG | NON_NEGATIVE_DERIVATIVE |
APPLICATION | sql.schema_changer.retry_errors | Counter of the number of retriable errors experienced by the schema changer | Errors | COUNTER | COUNT | AVG | NON_NEGATIVE_DERIVATIVE |
APPLICATION | sql.schema_changer.running | Gauge of currently running schema changes | Schema changes | GAUGE | COUNT | AVG | NONE |
diff --git a/pkg/sql/catalog/descs/collection.go b/pkg/sql/catalog/descs/collection.go
index ea37b462cc0c..b120845b9ffd 100644
--- a/pkg/sql/catalog/descs/collection.go
+++ b/pkg/sql/catalog/descs/collection.go
@@ -218,6 +218,23 @@ func (tc *Collection) HasUncommittedDescriptors() bool {
return tc.uncommitted.uncommitted.Len() > 0
}
+// HasUncommittedNewOrDroppedDescriptors returns true if the collection contains
+// any uncommitted descriptors that are newly created or dropped.
+func (tc *Collection) HasUncommittedNewOrDroppedDescriptors() bool {
+ isNewDescriptor := false
+ err := tc.uncommitted.iterateUncommittedByID(func(desc catalog.Descriptor) error {
+ if desc.GetVersion() == 1 || desc.Dropped() {
+ isNewDescriptor = true
+ return iterutil.StopIteration()
+ }
+ return nil
+ })
+ if err != nil {
+ return false
+ }
+ return isNewDescriptor
+}
+
// HasUncommittedTypes returns true if the Collection contains uncommitted
// types.
func (tc *Collection) HasUncommittedTypes() (has bool) {
diff --git a/pkg/sql/conn_executor.go b/pkg/sql/conn_executor.go
index 0a19c899d529..73093c0030df 100644
--- a/pkg/sql/conn_executor.go
+++ b/pkg/sql/conn_executor.go
@@ -4028,7 +4028,12 @@ func (ex *connExecutor) txnStateTransitionsApplyWrapper(
}(); err != nil {
return ai, err
}
-
+ if ex.extraTxnState.descCollection.HasUncommittedNewOrDroppedDescriptors() {
+ execCfg := ex.planner.ExecCfg()
+ if err := UpdateDescriptorCount(ex.Ctx(), execCfg, execCfg.SchemaChangerMetrics); err != nil {
+ log.Warningf(ex.Ctx(), "failed to scan descriptor table: %v", err)
+ }
+ }
fallthrough
case txnRollback:
ex.resetExtraTxnState(ex.Ctx(), advInfo.txnEvent, payloadErr)
diff --git a/pkg/sql/isql/isql_db.go b/pkg/sql/isql/isql_db.go
index fb60ce68e89d..9d8ffaf91d71 100644
--- a/pkg/sql/isql/isql_db.go
+++ b/pkg/sql/isql/isql_db.go
@@ -87,7 +87,7 @@ type Executor interface {
) (int, error)
// QueryRow executes the supplied SQL statement and returns a single row, or
- // nil if no row is found, or an error if more that one row is returned.
+ // nil if no row is found, or an error if more than one row is returned.
//
// QueryRow is deprecated. Use QueryRowEx() instead.
QueryRow(
diff --git a/pkg/sql/schema_changer.go b/pkg/sql/schema_changer.go
index 74a3c35486e6..22c8bf69db69 100644
--- a/pkg/sql/schema_changer.go
+++ b/pkg/sql/schema_changer.go
@@ -3341,3 +3341,20 @@ func (p *planner) CanCreateCrossDBSequenceRef() error {
}
return nil
}
+
+// UpdateDescriptorCount updates our sql.schema_changer.object_count gauge with
+// a fresh count of objects in the system.descriptor table.
+func UpdateDescriptorCount(
+ ctx context.Context, execCfg *ExecutorConfig, metric *SchemaChangerMetrics,
+) error {
+ return DescsTxn(ctx, execCfg, func(ctx context.Context, txn isql.Txn, col *descs.Collection) error {
+ row, err := txn.QueryRow(ctx, "sql-schema-changer-object-count", txn.KV(),
+ `SELECT count(*) FROM system.descriptor`)
+ if err != nil {
+ return err
+ }
+ count := *row[0].(*tree.DInt)
+ metric.ObjectCount.Update(int64(count))
+ return nil
+ })
+}
diff --git a/pkg/sql/schema_changer_metrics.go b/pkg/sql/schema_changer_metrics.go
index 4356c382f614..e1c78a00059f 100644
--- a/pkg/sql/schema_changer_metrics.go
+++ b/pkg/sql/schema_changer_metrics.go
@@ -38,6 +38,12 @@ var (
Measurement: "Errors",
Unit: metric.Unit_COUNT,
}
+ metaObjects = metric.Metadata{
+ Name: "sql.schema_changer.object_count",
+ Help: "Counter of the number of objects in the cluster",
+ Measurement: "Objects",
+ Unit: metric.Unit_COUNT,
+ }
)
// SchemaChangerMetrics are metrics corresponding to the schema changer.
@@ -48,6 +54,7 @@ type SchemaChangerMetrics struct {
PermanentErrors *metric.Counter
ConstraintErrors telemetry.Counter
UncategorizedErrors telemetry.Counter
+ ObjectCount *metric.Gauge
}
// MetricStruct makes SchemaChangerMetrics a metric.Struct.
@@ -64,5 +71,6 @@ func NewSchemaChangerMetrics() *SchemaChangerMetrics {
PermanentErrors: metric.NewCounter(metaPermanentErrors),
ConstraintErrors: sqltelemetry.SchemaChangeErrorCounter("constraint_violation"),
UncategorizedErrors: sqltelemetry.SchemaChangeErrorCounter("uncategorized"),
+ ObjectCount: metric.NewGauge(metaObjects),
}
}