Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/infoschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ var tableStatementsSummaryCols = []columnInfo{
{name: stmtsummary.TableNamesStr, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Involved tables"},
{name: stmtsummary.IndexNamesStr, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Used indices"},
{name: stmtsummary.SampleUserStr, tp: mysql.TypeVarchar, size: 64, comment: "Sampled user who executed these statements"},
{name: stmtsummary.UserStr, tp: mysql.TypeVarchar, size: 64, comment: "User that groups this summary when tidb_stmt_summary_group_by_user is ON"},
{name: stmtsummary.ExecCountStr, tp: mysql.TypeLonglong, size: 20, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Count of executions"},
{name: stmtsummary.SumErrorsStr, tp: mysql.TypeLong, size: 11, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Sum of errors"},
{name: stmtsummary.SumWarningsStr, tp: mysql.TypeLong, size: 11, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Sum of warnings"},
Expand Down Expand Up @@ -1447,6 +1448,7 @@ var tableTiDBStatementsStatsCols = []columnInfo{
{name: stmtsummary.TableNamesStr, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Involved tables"},
{name: stmtsummary.IndexNamesStr, tp: mysql.TypeBlob, size: types.UnspecifiedLength, comment: "Used indices"},
{name: stmtsummary.SampleUserStr, tp: mysql.TypeVarchar, size: 64, comment: "Sampled user who executed these statements"},
{name: stmtsummary.UserStr, tp: mysql.TypeVarchar, size: 64, comment: "User that groups this summary when tidb_stmt_summary_group_by_user is ON"},
{name: stmtsummary.ExecCountStr, tp: mysql.TypeLonglong, size: 20, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Count of executions"},
{name: stmtsummary.ErrorsStr, tp: mysql.TypeLong, size: 11, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Sum of errors"},
{name: stmtsummary.WarningsStr, tp: mysql.TypeLong, size: 11, flag: mysql.NotNullFlag | mysql.UnsignedFlag, comment: "Sum of warnings"},
Expand Down
6 changes: 6 additions & 0 deletions pkg/sessionctx/vardef/tidb_vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,11 @@ const (
// TiDBStmtSummaryMaxSQLLength indicates the max length of displayed normalized sql and sample sql.
TiDBStmtSummaryMaxSQLLength = "tidb_stmt_summary_max_sql_length"

// TiDBStmtSummaryGroupByUser, when enabled, adds the executing user to the
// statement summary grouping key so the same digest run by different users
// produces separate rows. Off by default to avoid cardinality growth.
TiDBStmtSummaryGroupByUser = "tidb_stmt_summary_group_by_user"

// TiDBIgnoreInlistPlanDigest enables TiDB to generate the same plan digest with SQL using different in-list arguments.
TiDBIgnoreInlistPlanDigest = "tidb_ignore_inlist_plan_digest"

Expand Down Expand Up @@ -1588,6 +1593,7 @@ const (
DefTiDBStmtSummaryHistorySize = 24
DefTiDBStmtSummaryMaxStmtCount = 3000
DefTiDBStmtSummaryMaxSQLLength = 32768
DefTiDBStmtSummaryGroupByUser = false
DefTiDBCapturePlanBaseline = Off
DefTiDBIgnoreInlistPlanDigest = true
DefTiDBEnableIndexMerge = true
Expand Down
4 changes: 4 additions & 0 deletions pkg/sessionctx/variable/sysvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,10 @@ var defaultSysVars = []*SysVar{
SetGlobal: func(_ context.Context, s *SessionVars, val string) error {
return stmtsummaryv2.SetMaxSQLLength(TidbOptInt(val, vardef.DefTiDBStmtSummaryMaxSQLLength))
}},
{Scope: vardef.ScopeGlobal, Name: vardef.TiDBStmtSummaryGroupByUser, Value: BoolToOnOff(vardef.DefTiDBStmtSummaryGroupByUser), Type: vardef.TypeBool, AllowEmpty: true,
SetGlobal: func(_ context.Context, s *SessionVars, val string) error {
return stmtsummaryv2.SetGroupByUser(TiDBOptOn(val))
}},
{Scope: vardef.ScopeGlobal, Name: vardef.TiDBCapturePlanBaseline, Value: vardef.DefTiDBCapturePlanBaseline, Type: vardef.TypeBool, AllowEmptyAll: true},
{Scope: vardef.ScopeGlobal, Name: vardef.TiDBEvolvePlanTaskMaxTime, Value: strconv.Itoa(vardef.DefTiDBEvolvePlanTaskMaxTime), Type: vardef.TypeInt, MinValue: -1, MaxValue: math.MaxInt64},
{Scope: vardef.ScopeGlobal, Name: vardef.TiDBEvolvePlanTaskStartTime, Value: vardef.DefTiDBEvolvePlanTaskStartTime, Type: vardef.TypeTime},
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/stmtsummary/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ go_test(
],
embed = [":stmtsummary"],
flaky = True,
shard_count = 24,
shard_count = 25,
deps = [
"//pkg/meta/model",
"//pkg/parser/ast",
Expand Down
4 changes: 2 additions & 2 deletions pkg/util/stmtsummary/evicted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func newInduceSsbde(beginTime int64, endTime int64) *stmtSummaryByDigestElement
// generate new StmtDigestKey and stmtSummaryByDigest
func generateStmtSummaryByDigestKeyValue(schema string, beginTime int64, endTime int64) (*StmtDigestKey, *stmtSummaryByDigest) {
key := &StmtDigestKey{}
key.Init(schema, "", "", "", "")
key.Init(schema, "", "", "", "", "")
value := newInduceSsbd(beginTime, endTime)
return key, value
}
Expand Down Expand Up @@ -191,7 +191,7 @@ func TestSimpleStmtSummaryByDigestEvicted(t *testing.T) {
require.Equal(t, "{begin: 8, end: 9, count: 1}, {begin: 5, end: 6, count: 1}, {begin: 2, end: 3, count: 1}", getAllEvicted(ssbde))

evictedKey = &StmtDigestKey{}
evictedKey.Init("b", "", "", "", "")
evictedKey.Init("b", "", "", "", "", "")
ssbde.AddEvicted(evictedKey, evictedValue, 4)
require.Equal(t, "{begin: 8, end: 9, count: 2}, {begin: 5, end: 6, count: 2}, {begin: 2, end: 3, count: 2}, {begin: 1, end: 2, count: 1}", getAllEvicted(ssbde))

Expand Down
4 changes: 4 additions & 0 deletions pkg/util/stmtsummary/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ const (
TableNamesStr = "TABLE_NAMES"
IndexNamesStr = "INDEX_NAMES"
SampleUserStr = "SAMPLE_USER"
UserStr = "USER"
ExecCountStr = "EXEC_COUNT"
SumErrorsStr = "SUM_ERRORS"
SumWarningsStr = "SUM_WARNINGS"
Expand Down Expand Up @@ -487,6 +488,9 @@ var columnValueFactoryMap = map[string]columnValueFactory{
}
return convertEmptyToNil(sampleUser)
},
UserStr: func(_ *stmtSummaryReader, _ *stmtSummaryByDigestElement, ssbd *stmtSummaryByDigest, _ *stmtSummaryStats) any {
return convertEmptyToNil(ssbd.user)
},
ExecCountStr: func(_ *stmtSummaryReader, _ *stmtSummaryByDigestElement, _ *stmtSummaryByDigest, ssStats *stmtSummaryStats) any {
return ssStats.execCount
},
Expand Down
37 changes: 34 additions & 3 deletions pkg/util/stmtsummary/statement_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ type StmtDigestKey struct {
}

// Init initialize the hash key.
func (key *StmtDigestKey) Init(schemaName, digest, prevDigest, planDigest, resourceGroupName string) {
length := len(schemaName) + len(digest) + len(prevDigest) + len(planDigest) + len(resourceGroupName)
// When group_by_user is disabled, callers should pass an empty string for user,
// so the hash matches pre-user-dimension behavior.
func (key *StmtDigestKey) Init(schemaName, digest, prevDigest, planDigest, resourceGroupName, user string) {
length := len(schemaName) + len(digest) + len(prevDigest) + len(planDigest) + len(resourceGroupName) + len(user)
if cap(key.hash) < length {
key.hash = make([]byte, 0, length)
} else {
Expand All @@ -64,6 +66,7 @@ func (key *StmtDigestKey) Init(schemaName, digest, prevDigest, planDigest, resou
key.hash = append(key.hash, hack.Slice(prevDigest)...)
key.hash = append(key.hash, hack.Slice(planDigest)...)
key.hash = append(key.hash, hack.Slice(resourceGroupName)...)
key.hash = append(key.hash, hack.Slice(user)...)
}

// Hash implements SimpleLRUCache.Key.
Expand All @@ -89,6 +92,7 @@ type stmtSummaryByDigestMap struct {
optRefreshInterval *atomic2.Int64
optHistorySize *atomic2.Int32
optMaxSQLLength *atomic2.Int32
optGroupByUser *atomic2.Bool

// other stores summary of evicted data.
other *stmtSummaryByDigestEvicted
Expand Down Expand Up @@ -117,6 +121,9 @@ type stmtSummaryByDigest struct {
isInternal bool
bindingSQL string
bindingDigest string
// user is populated when group_by_user is enabled at creation time.
// When disabled, it is empty and not part of the grouping key.
user string
}

// stmtSummaryByDigestElement is the summary for each type of statements in current interval.
Expand Down Expand Up @@ -318,6 +325,7 @@ func newStmtSummaryByDigestMap() *stmtSummaryByDigestMap {
optRefreshInterval: atomic2.NewInt64(1800),
optHistorySize: atomic2.NewInt32(24),
optMaxSQLLength: atomic2.NewInt32(32768),
optGroupByUser: atomic2.NewBool(false),
other: ssbde,
}
newSsMap.summaryMap.SetOnEvict(func(k kvcache.Key, v kvcache.Value) {
Expand Down Expand Up @@ -349,9 +357,14 @@ func (ssMap *stmtSummaryByDigestMap) AddStatement(sei *StmtExecInfo) {
historySize = ssMap.historySize()
}

userForKey := ""
if ssMap.optGroupByUser.Load() {
userForKey = sei.User
}

key := StmtDigestKeyPool.Get().(*StmtDigestKey)
// Init hash value in advance, to reduce the time holding the lock.
key.Init(sei.SchemaName, sei.Digest, sei.PrevSQLDigest, sei.PlanDigest, sei.ResourceGroupName)
key.Init(sei.SchemaName, sei.Digest, sei.PrevSQLDigest, sei.PlanDigest, sei.ResourceGroupName, userForKey)
Comment thread
nolouch marked this conversation as resolved.
Outdated

var exist bool

Expand Down Expand Up @@ -386,6 +399,7 @@ func (ssMap *stmtSummaryByDigestMap) AddStatement(sei *StmtExecInfo) {
if !exist {
// Lazy initialize it to release ssMap.mutex ASAP.
summary = new(stmtSummaryByDigest)
summary.user = userForKey
ssMap.summaryMap.Put(key, summary)
} else {
summary = value.(*stmtSummaryByDigest)
Expand Down Expand Up @@ -508,6 +522,23 @@ func (ssMap *stmtSummaryByDigestMap) historySize() int {
return int(ssMap.optHistorySize.Load())
}

// SetGroupByUser enables or disables grouping statement summaries by the
// executing user. Switching the flag clears existing data because existing
// rows were aggregated under a different grouping key.
func (ssMap *stmtSummaryByDigestMap) SetGroupByUser(value bool) error {
if ssMap.optGroupByUser.Load() == value {
return nil
}
ssMap.optGroupByUser.Store(value)
ssMap.Clear()
return nil
}

// GroupByUser reports whether statement summaries are grouped by user.
func (ssMap *stmtSummaryByDigestMap) GroupByUser() bool {
return ssMap.optGroupByUser.Load()
}

// SetHistorySize sets the history size for all summaries.
func (ssMap *stmtSummaryByDigestMap) SetMaxStmtCount(value uint) error {
// `optMaxStmtCount` and `ssMap` don't need to be strictly atomically updated.
Expand Down
69 changes: 56 additions & 13 deletions pkg/util/stmtsummary/statement_summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestAddStatement(t *testing.T) {
stmtExecInfo1 := generateAnyExecInfo()
stmtExecInfo1.ExecDetail.CommitDetail.Mu.PrewriteBackoffTypes = make([]string, 0)
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
samplePlan, _, _ := stmtExecInfo1.LazyInfo.GetEncodedPlan()
stmtExecInfo1.ExecDetail.CommitDetail.Mu.Lock()
expectedSummaryElement := stmtSummaryByDigestElement{
Expand Down Expand Up @@ -485,7 +485,7 @@ func TestAddStatement(t *testing.T) {
stmtExecInfo4.SchemaName = "schema2"
stmtExecInfo4.ExecDetail.CommitDetail = nil
key = &StmtDigestKey{}
key.Init(stmtExecInfo4.SchemaName, stmtExecInfo4.Digest, "", stmtExecInfo4.PlanDigest, stmtExecInfo4.ResourceGroupName)
key.Init(stmtExecInfo4.SchemaName, stmtExecInfo4.Digest, "", stmtExecInfo4.PlanDigest, stmtExecInfo4.ResourceGroupName, "")
ssMap.AddStatement(stmtExecInfo4)
require.Equal(t, 2, ssMap.summaryMap.Size())
_, ok = ssMap.summaryMap.Get(key)
Expand All @@ -495,7 +495,7 @@ func TestAddStatement(t *testing.T) {
stmtExecInfo5 := stmtExecInfo1
stmtExecInfo5.Digest = "digest2"
key = &StmtDigestKey{}
key.Init(stmtExecInfo5.SchemaName, stmtExecInfo5.Digest, "", stmtExecInfo5.PlanDigest, stmtExecInfo5.ResourceGroupName)
key.Init(stmtExecInfo5.SchemaName, stmtExecInfo5.Digest, "", stmtExecInfo5.PlanDigest, stmtExecInfo5.ResourceGroupName, "")
ssMap.AddStatement(stmtExecInfo5)
require.Equal(t, 3, ssMap.summaryMap.Size())
_, ok = ssMap.summaryMap.Get(key)
Expand All @@ -505,7 +505,7 @@ func TestAddStatement(t *testing.T) {
stmtExecInfo6 := stmtExecInfo1
stmtExecInfo6.PlanDigest = "plan_digest2"
key = &StmtDigestKey{}
key.Init(stmtExecInfo6.SchemaName, stmtExecInfo6.Digest, "", stmtExecInfo6.PlanDigest, stmtExecInfo6.ResourceGroupName)
key.Init(stmtExecInfo6.SchemaName, stmtExecInfo6.Digest, "", stmtExecInfo6.PlanDigest, stmtExecInfo6.ResourceGroupName, "")
ssMap.AddStatement(stmtExecInfo6)
require.Equal(t, 4, ssMap.summaryMap.Size())
_, ok = ssMap.summaryMap.Get(key)
Expand All @@ -528,7 +528,7 @@ func TestAddStatement(t *testing.T) {
bindingSQL: originalSQL,
}
key = &StmtDigestKey{}
key.Init(stmtExecInfo7.SchemaName, stmtExecInfo7.Digest, "", stmtExecInfo7.PlanDigest, stmtExecInfo7.ResourceGroupName)
key.Init(stmtExecInfo7.SchemaName, stmtExecInfo7.Digest, "", stmtExecInfo7.PlanDigest, stmtExecInfo7.ResourceGroupName, "")
ssMap.AddStatement(stmtExecInfo7)
require.Equal(t, 5, ssMap.summaryMap.Size())
v, ok := ssMap.summaryMap.Get(key)
Expand Down Expand Up @@ -1100,7 +1100,7 @@ func TestMaxStmtCount(t *testing.T) {
// LRU cache should work.
for i := loops - 10; i < loops; i++ {
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, fmt.Sprintf("digest%d", i), "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, fmt.Sprintf("digest%d", i), "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
key.Hash()
_, ok := sm.Get(key)
require.True(t, ok)
Expand Down Expand Up @@ -1144,7 +1144,7 @@ func TestMaxSQLLength(t *testing.T) {
ssMap.AddStatement(stmtExecInfo1)

key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
value, ok := ssMap.summaryMap.Get(key)
require.True(t, ok)

Expand Down Expand Up @@ -1337,7 +1337,7 @@ func TestRefreshCurrentSummary(t *testing.T) {
ssMap.beginTimeForCurInterval = now + 10
stmtExecInfo1 := generateAnyExecInfo()
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
ssMap.AddStatement(stmtExecInfo1)
require.Equal(t, 1, ssMap.summaryMap.Size())
value, ok := ssMap.summaryMap.Get(key)
Expand Down Expand Up @@ -1384,7 +1384,7 @@ func TestSummaryHistory(t *testing.T) {

stmtExecInfo1 := generateAnyExecInfo()
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
for i := range 11 {
ssMap.beginTimeForCurInterval = now + int64(i+1)*10
ssMap.AddStatement(stmtExecInfo1)
Expand Down Expand Up @@ -1453,7 +1453,7 @@ func TestPrevSQL(t *testing.T) {
stmtExecInfo1.PrevSQLDigest = "prevSQLDigest"
ssMap.AddStatement(stmtExecInfo1)
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, stmtExecInfo1.PrevSQLDigest, stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, stmtExecInfo1.PrevSQLDigest, stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
require.Equal(t, 1, ssMap.summaryMap.Size())
_, ok := ssMap.summaryMap.Get(key)
require.True(t, ok)
Expand All @@ -1468,7 +1468,7 @@ func TestPrevSQL(t *testing.T) {
stmtExecInfo2.PrevSQLDigest = "prevSQLDigest1"
ssMap.AddStatement(stmtExecInfo2)
require.Equal(t, 2, ssMap.summaryMap.Size())
key.Init(stmtExecInfo2.SchemaName, stmtExecInfo2.Digest, stmtExecInfo2.PrevSQLDigest, stmtExecInfo2.PlanDigest, stmtExecInfo2.ResourceGroupName)
key.Init(stmtExecInfo2.SchemaName, stmtExecInfo2.Digest, stmtExecInfo2.PrevSQLDigest, stmtExecInfo2.PlanDigest, stmtExecInfo2.ResourceGroupName, "")
_, ok = ssMap.summaryMap.Get(key)
require.True(t, ok)
}
Expand All @@ -1481,7 +1481,7 @@ func TestEndTime(t *testing.T) {
stmtExecInfo1 := generateAnyExecInfo()
ssMap.AddStatement(stmtExecInfo1)
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", stmtExecInfo1.PlanDigest, stmtExecInfo1.ResourceGroupName, "")
require.Equal(t, 1, ssMap.summaryMap.Size())
value, ok := ssMap.summaryMap.Get(key)
require.True(t, ok)
Expand Down Expand Up @@ -1527,7 +1527,7 @@ func TestPointGet(t *testing.T) {
stmtExecInfo1.LazyInfo.(*mockLazyInfo).plan = fakePlanDigestGenerator()
ssMap.AddStatement(stmtExecInfo1)
key := &StmtDigestKey{}
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", "", stmtExecInfo1.ResourceGroupName)
key.Init(stmtExecInfo1.SchemaName, stmtExecInfo1.Digest, "", "", stmtExecInfo1.ResourceGroupName, "")
require.Equal(t, 1, ssMap.summaryMap.Size())
value, ok := ssMap.summaryMap.Get(key)
require.True(t, ok)
Expand Down Expand Up @@ -1606,3 +1606,46 @@ func TestAccessPrivilege(t *testing.T) {
datums = reader.GetStmtSummaryCurrentRows()
require.Len(t, datums, loops)
}

// TestAddStatementGroupByUser verifies that flipping the group-by-user flag
// splits the same digest into per-user rows and fills ssbd.user. The default
// (flag OFF) keeps legacy behavior: one row per digest regardless of user.
func TestAddStatementGroupByUser(t *testing.T) {
ssMap := newStmtSummaryByDigestMap()

info1 := generateAnyExecInfo()
info1.User = "alice"
info2 := generateAnyExecInfo()
info2.User = "bob"

// Flag off: both statements collapse into one record.
ssMap.AddStatement(info1)
ssMap.AddStatement(info2)
require.Equal(t, 1, ssMap.summaryMap.Size())

// Flipping the flag clears prior data (different grouping key).
require.NoError(t, ssMap.SetGroupByUser(true))
require.Equal(t, 0, ssMap.summaryMap.Size())

ssMap.AddStatement(info1)
ssMap.AddStatement(info2)
ssMap.AddStatement(info1)
require.Equal(t, 2, ssMap.summaryMap.Size())

seen := map[string]bool{}
for _, v := range ssMap.summaryMap.Values() {
ssbd := v.(*stmtSummaryByDigest)
seen[ssbd.user] = true
}
require.True(t, seen["alice"])
require.True(t, seen["bob"])

// Flipping back off clears again, and new records keep user empty.
require.NoError(t, ssMap.SetGroupByUser(false))
require.Equal(t, 0, ssMap.summaryMap.Size())
ssMap.AddStatement(info1)
require.Equal(t, 1, ssMap.summaryMap.Size())
for _, v := range ssMap.summaryMap.Values() {
require.Empty(t, v.(*stmtSummaryByDigest).user)
}
}
2 changes: 1 addition & 1 deletion pkg/util/stmtsummary/v2/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ go_test(
],
embed = [":stmtsummary"],
flaky = True,
shard_count = 13,
shard_count = 14,
deps = [
"//pkg/meta/model",
"//pkg/parser/ast",
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/stmtsummary/v2/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
TableNamesStr = "TABLE_NAMES"
IndexNamesStr = "INDEX_NAMES"
SampleUserStr = "SAMPLE_USER"
UserStr = "USER"
ExecCountStr = "EXEC_COUNT"
SumErrorsStr = "SUM_ERRORS"
SumWarningsStr = "SUM_WARNINGS"
Expand Down Expand Up @@ -212,6 +213,9 @@ var columnFactoryMap = map[string]columnFactory{
}
return convertEmptyToNil(sampleUser)
},
UserStr: func(_ columnInfo, record *StmtRecord) any {
return convertEmptyToNil(record.User)
},
ExecCountStr: func(_ columnInfo, record *StmtRecord) any {
return record.ExecCount
},
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/stmtsummary/v2/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ type StmtRecord struct {
IsInternal bool `json:"is_internal"`
BindingSQL string `json:"binding_sql"`
BindingDigest string `json:"binding_digest"`
// User is populated from StmtExecInfo.User at record creation when
// group_by_user is enabled; otherwise empty. Once set it never changes,
// because records with different users live in different grouping buckets.
User string `json:"user,omitempty"`
// Basic
SampleSQL string `json:"sample_sql"`
Charset string `json:"charset"`
Expand Down
Loading