diff --git a/executor/adapter.go b/executor/adapter.go index d56b26e63b1c7..b1a759cc1be27 100644 --- a/executor/adapter.go +++ b/executor/adapter.go @@ -189,8 +189,9 @@ func (a *recordSet) OnFetchReturned() { // TelemetryInfo records some telemetry information during execution. type TelemetryInfo struct { - UseNonRecursive bool - UseRecursive bool + UseNonRecursive bool + UseRecursive bool + UseMultiSchemaChange bool } // ExecStmt implements the sqlexec.Statement interface, it builds a planner.Plan to an sqlexec.Statement. diff --git a/executor/builder.go b/executor/builder.go index fd4e47c45a777..da3ba39fb2622 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -983,6 +983,12 @@ func (b *executorBuilder) buildRevoke(revoke *ast.RevokeStmt) Executor { } func (b *executorBuilder) buildDDL(v *plannercore.DDL) Executor { + switch v.Statement.(type) { + case *ast.AlterTableStmt: + if len(v.Statement.(*ast.AlterTableStmt).Specs) > 1 && b.Ti != nil { + b.Ti.UseMultiSchemaChange = true + } + } e := &DDLExec{ baseExecutor: newBaseExecutor(b.ctx, v.Schema(), v.ID()), stmt: v.Statement, diff --git a/metrics/telemetry.go b/metrics/telemetry.go index 10bf1ac8b624e..79bcbf7c9f9a1 100644 --- a/metrics/telemetry.go +++ b/metrics/telemetry.go @@ -28,6 +28,13 @@ var ( Name: "non_recursive_cte_usage", Help: "Counter of usage of CTE", }, []string{LblCTEType}) + TelemetryMultiSchemaChangeCnt = prometheus.NewCounter( + prometheus.CounterOpts{ + Namespace: "tidb", + Subsystem: "telemetry", + Name: "multi_schema_change_usage", + Help: "Counter of usage of multi-schema change", + }) ) // readCounter reads the value of a prometheus.Counter. @@ -68,6 +75,25 @@ func GetCTECounter() CTEUsageCounter { } } +// MultiSchemaChangeUsageCounter records the usages of multi-schema change. +type MultiSchemaChangeUsageCounter struct { + MultiSchemaChangeUsed int64 `json:"multi_schema_change_used"` +} + +// Sub returns the difference of two counters. +func (c MultiSchemaChangeUsageCounter) Sub(rhs MultiSchemaChangeUsageCounter) MultiSchemaChangeUsageCounter { + return MultiSchemaChangeUsageCounter{ + MultiSchemaChangeUsed: c.MultiSchemaChangeUsed - rhs.MultiSchemaChangeUsed, + } +} + +// GetMultiSchemaCounter gets the TxnCommitCounter. +func GetMultiSchemaCounter() MultiSchemaChangeUsageCounter { + return MultiSchemaChangeUsageCounter{ + MultiSchemaChangeUsed: readCounter(TelemetryMultiSchemaChangeCnt), + } +} + // NonTransactionalStmtCounter records the usages of non-transactional statements. type NonTransactionalStmtCounter struct { DeleteCount int64 `json:"delete"` diff --git a/session/session.go b/session/session.go index 5bd84ac996ef0..4c2eecfc5dcdc 100644 --- a/session/session.go +++ b/session/session.go @@ -122,7 +122,8 @@ var ( sessionExecuteParseDurationInternal = metrics.SessionExecuteParseDuration.WithLabelValues(metrics.LblInternal) sessionExecuteParseDurationGeneral = metrics.SessionExecuteParseDuration.WithLabelValues(metrics.LblGeneral) - telemetryCTEUsage = metrics.TelemetrySQLCTECnt + telemetryCTEUsage = metrics.TelemetrySQLCTECnt + telemetryMultiSchemaChangeUsage = metrics.TelemetryMultiSchemaChangeCnt ) // Session context, it is consistent with the lifecycle of a client connection. @@ -3421,6 +3422,10 @@ func (s *session) updateTelemetryMetric(es *executor.ExecStmt) { } else { telemetryCTEUsage.WithLabelValues("notCTE").Inc() } + + if ti.UseMultiSchemaChange { + telemetryMultiSchemaChangeUsage.Inc() + } } // GetBuiltinFunctionUsage returns the replica of counting of builtin function usage diff --git a/telemetry/data.go b/telemetry/data.go index 048d458797966..49bac14ce69f8 100644 --- a/telemetry/data.go +++ b/telemetry/data.go @@ -60,6 +60,7 @@ func generateTelemetryData(sctx sessionctx.Context, trackingID string) telemetry func postReportTelemetryData() { postReportTxnUsage() postReportCTEUsage() + postReportMultiSchemaChangeUsage() postReportSlowQueryStats() postReportNonTransactionalCounter() } diff --git a/telemetry/data_feature_usage.go b/telemetry/data_feature_usage.go index af5412afbc910..bc73153a84e15 100644 --- a/telemetry/data_feature_usage.go +++ b/telemetry/data_feature_usage.go @@ -37,15 +37,16 @@ type featureUsage struct { Txn *TxnUsage `json:"txn"` // cluster index usage information // key is the first 6 characters of sha2(TABLE_NAME, 256) - ClusterIndex *ClusterIndexUsage `json:"clusterIndex"` - NewClusterIndex *NewClusterIndexUsage `json:"newClusterIndex"` - TemporaryTable bool `json:"temporaryTable"` - CTE *m.CTEUsageCounter `json:"cte"` - CachedTable bool `json:"cachedTable"` - AutoCapture bool `json:"autoCapture"` - PlacementPolicyUsage *placementPolicyUsage `json:"placementPolicy"` - NonTransactionalUsage *m.NonTransactionalStmtCounter `json:"nonTransactional"` - GlobalKill bool `json:"globalKill"` + ClusterIndex *ClusterIndexUsage `json:"clusterIndex"` + NewClusterIndex *NewClusterIndexUsage `json:"newClusterIndex"` + TemporaryTable bool `json:"temporaryTable"` + CTE *m.CTEUsageCounter `json:"cte"` + CachedTable bool `json:"cachedTable"` + AutoCapture bool `json:"autoCapture"` + PlacementPolicyUsage *placementPolicyUsage `json:"placementPolicy"` + NonTransactionalUsage *m.NonTransactionalStmtCounter `json:"nonTransactional"` + GlobalKill bool `json:"globalKill"` + MultiSchemaChange *m.MultiSchemaChangeUsageCounter `json:"multiSchemaChange"` } type placementPolicyUsage struct { @@ -70,6 +71,8 @@ func getFeatureUsage(ctx context.Context, sctx sessionctx.Context) (*featureUsag usage.CTE = getCTEUsageInfo() + usage.MultiSchemaChange = getMultiSchemaChangeUsageInfo() + usage.AutoCapture = getAutoCaptureUsageInfo(sctx) collectFeatureUsageFromInfoschema(sctx, &usage) @@ -201,6 +204,7 @@ type TxnUsage struct { var initialTxnCommitCounter metrics.TxnCommitCounter var initialCTECounter m.CTEUsageCounter var initialNonTransactionalCounter m.NonTransactionalStmtCounter +var initialMultiSchemaChangeCounter m.MultiSchemaChangeUsageCounter // getTxnUsageInfo gets the usage info of transaction related features. It's exported for tests. func getTxnUsageInfo(ctx sessionctx.Context) *TxnUsage { @@ -233,7 +237,6 @@ func postReportTxnUsage() { initialTxnCommitCounter = metrics.GetTxnCommitCounter() } -// ResetCTEUsage resets CTE usages. func postReportCTEUsage() { initialCTECounter = m.GetCTECounter() } @@ -245,6 +248,16 @@ func getCTEUsageInfo() *m.CTEUsageCounter { return &diff } +func postReportMultiSchemaChangeUsage() { + initialMultiSchemaChangeCounter = m.GetMultiSchemaCounter() +} + +func getMultiSchemaChangeUsageInfo() *m.MultiSchemaChangeUsageCounter { + curr := m.GetMultiSchemaCounter() + diff := curr.Sub(initialMultiSchemaChangeCounter) + return &diff +} + // getAutoCaptureUsageInfo gets the 'Auto Capture' usage func getAutoCaptureUsageInfo(ctx sessionctx.Context) bool { if val, err := variable.GetGlobalSystemVar(ctx.GetSessionVars(), variable.TiDBCapturePlanBaseline); err == nil { diff --git a/telemetry/data_feature_usage_test.go b/telemetry/data_feature_usage_test.go index 58198b5083d84..d89928bbcc19d 100644 --- a/telemetry/data_feature_usage_test.go +++ b/telemetry/data_feature_usage_test.go @@ -127,6 +127,40 @@ func TestCachedTable(t *testing.T) { require.False(t, usage.CachedTable) } +func TestMultiSchemaChange(t *testing.T) { + store, clean := testkit.CreateMockStore(t) + defer clean() + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + + usage, err := telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(0), usage.MultiSchemaChange.MultiSchemaChangeUsed) + + tk.MustExec("drop table if exists tele_multi_t") + tk.MustExec("create table tele_multi_t(id int)") + tk.MustExec("alter table tele_multi_t add column b int") + usage, err = telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(0), usage.MultiSchemaChange.MultiSchemaChangeUsed) + + tk.MustExec("alter table tele_multi_t add column c int, drop column b") + usage, err = telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(1), usage.MultiSchemaChange.MultiSchemaChangeUsed) + + tk.MustExec("alter table tele_multi_t add column b int, drop column c") + usage, err = telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(2), usage.MultiSchemaChange.MultiSchemaChangeUsed) + + tk.MustExec("alter table tele_multi_t drop column b") + usage, err = telemetry.GetFeatureUsage(tk.Session()) + require.NoError(t, err) + require.Equal(t, int64(2), usage.MultiSchemaChange.MultiSchemaChangeUsed) +} + func TestPlacementPolicies(t *testing.T) { store, clean := testkit.CreateMockStore(t) defer clean()