Skip to content

Commit a3e1d01

Browse files
djshow832sre-bot
authored andcommitted
infoschema, session: support for events_statements_summary_by_digest #12017 (#12306)
1 parent 45d7da0 commit a3e1d01

20 files changed

+928
-13
lines changed

config/config.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ type Config struct {
8888
CheckMb4ValueInUTF8 bool `toml:"check-mb4-value-in-utf8" json:"check-mb4-value-in-utf8"`
8989
// TreatOldVersionUTF8AsUTF8MB4 is use to treat old version table/column UTF8 charset as UTF8MB4. This is for compatibility.
9090
// Currently not support dynamic modify, because this need to reload all old version schema.
91-
TreatOldVersionUTF8AsUTF8MB4 bool `toml:"treat-old-version-utf8-as-utf8mb4" json:"treat-old-version-utf8-as-utf8mb4"`
92-
SplitRegionMaxNum uint64 `toml:"split-region-max-num" json:"split-region-max-num"`
91+
TreatOldVersionUTF8AsUTF8MB4 bool `toml:"treat-old-version-utf8-as-utf8mb4" json:"treat-old-version-utf8-as-utf8mb4"`
92+
SplitRegionMaxNum uint64 `toml:"split-region-max-num" json:"split-region-max-num"`
93+
StmtSummary StmtSummary `toml:"stmt-summary" json:"stmt-summary"`
9394
}
9495

9596
// Log is the log section of config.
@@ -306,6 +307,14 @@ type PessimisticTxn struct {
306307
TTL string `toml:"ttl" json:"ttl"`
307308
}
308309

310+
// StmtSummary is the config for statement summary.
311+
type StmtSummary struct {
312+
// The maximum number of statements kept in memory.
313+
MaxStmtCount uint `toml:"max-stmt-count" json:"max-stmt-count"`
314+
// The maximum length of displayed normalized SQL and sample SQL.
315+
MaxSQLLength uint `toml:"max-sql-length" json:"max-sql-length"`
316+
}
317+
309318
var defaultConf = Config{
310319
Host: "0.0.0.0",
311320
AdvertiseAddress: "",
@@ -396,6 +405,10 @@ var defaultConf = Config{
396405
MaxRetryCount: 256,
397406
TTL: "40s",
398407
},
408+
StmtSummary: StmtSummary{
409+
MaxStmtCount: 100,
410+
MaxSQLLength: 4096,
411+
},
399412
}
400413

401414
var (

config/config.toml.example

+7
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,10 @@ max-retry-count = 256
300300
# default TTL in milliseconds for pessimistic lock.
301301
# The value must between "15s" and "120s".
302302
ttl = "40s"
303+
304+
[stmt-summary]
305+
# max number of statements kept in memory.
306+
max-stmt-count = 100
307+
308+
# max length of displayed normalized sql and sample sql.
309+
max-sql-length = 4096

config/config_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ split-region-max-num=10000
6565
[tikv-client]
6666
commit-timeout="41s"
6767
max-batch-size=128
68+
[stmt-summary]
69+
max-stmt-count=1000
70+
max-sql-length=1024
6871
`)
6972

7073
c.Assert(err, IsNil)
@@ -80,6 +83,8 @@ max-batch-size=128
8083
c.Assert(conf.TiKVClient.MaxBatchSize, Equals, uint(128))
8184
c.Assert(conf.TokenLimit, Equals, uint(1000))
8285
c.Assert(conf.SplitRegionMaxNum, Equals, uint64(10000))
86+
c.Assert(conf.StmtSummary.MaxStmtCount, Equals, uint(1000))
87+
c.Assert(conf.StmtSummary.MaxSQLLength, Equals, uint(1024))
8388
c.Assert(f.Close(), IsNil)
8489
c.Assert(os.Remove(configFile), IsNil)
8590

domain/global_vars_cache.go

+26
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import (
1818
"time"
1919

2020
"github.com/pingcap/parser/ast"
21+
"github.com/pingcap/tidb/sessionctx/variable"
2122
"github.com/pingcap/tidb/util/chunk"
23+
"github.com/pingcap/tidb/util/stmtsummary"
2224
)
2325

2426
// GlobalVariableCache caches global variables.
@@ -41,6 +43,8 @@ func (gvc *GlobalVariableCache) Update(rows []chunk.Row, fields []*ast.ResultFie
4143
gvc.rows = rows
4244
gvc.fields = fields
4345
gvc.Unlock()
46+
47+
checkEnableStmtSummary(rows, fields)
4448
}
4549

4650
// Get gets the global variables from cache.
@@ -63,6 +67,28 @@ func (gvc *GlobalVariableCache) Disable() {
6367
return
6468
}
6569

70+
// checkEnableStmtSummary looks for TiDBEnableStmtSummary and notifies StmtSummary
71+
func checkEnableStmtSummary(rows []chunk.Row, fields []*ast.ResultField) {
72+
for _, row := range rows {
73+
varName := row.GetString(0)
74+
if varName == variable.TiDBEnableStmtSummary {
75+
varVal := row.GetDatum(1, &fields[1].Column.FieldType)
76+
77+
sVal := ""
78+
if !varVal.IsNull() {
79+
var err error
80+
sVal, err = varVal.ToString()
81+
if err != nil {
82+
return
83+
}
84+
}
85+
86+
stmtsummary.OnEnableStmtSummaryModified(sVal)
87+
break
88+
}
89+
}
90+
}
91+
6692
// GetGlobalVarsCache gets the global variable cache.
6793
func (do *Domain) GetGlobalVarsCache() *GlobalVariableCache {
6894
return &do.gvc

domain/global_vars_cache_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
package domain
1515

1616
import (
17+
"sync/atomic"
1718
"time"
1819

1920
. "github.com/pingcap/check"
2021
"github.com/pingcap/parser/ast"
2122
"github.com/pingcap/parser/charset"
2223
"github.com/pingcap/parser/model"
2324
"github.com/pingcap/parser/mysql"
25+
"github.com/pingcap/tidb/sessionctx/variable"
2426
"github.com/pingcap/tidb/store/mockstore"
2527
"github.com/pingcap/tidb/types"
2628
"github.com/pingcap/tidb/util/chunk"
@@ -96,3 +98,47 @@ func getResultField(colName string, id, offset int) *ast.ResultField {
9698
DBName: model.NewCIStr("test"),
9799
}
98100
}
101+
102+
func (gvcSuite *testGVCSuite) TestCheckEnableStmtSummary(c *C) {
103+
defer testleak.AfterTest(c)()
104+
testleak.BeforeTest()
105+
106+
store, err := mockstore.NewMockTikvStore()
107+
c.Assert(err, IsNil)
108+
defer store.Close()
109+
ddlLease := 50 * time.Millisecond
110+
dom := NewDomain(store, ddlLease, 0, mockFactory)
111+
err = dom.Init(ddlLease, sysMockFactory)
112+
c.Assert(err, IsNil)
113+
defer dom.Close()
114+
115+
gvc := dom.GetGlobalVarsCache()
116+
117+
rf := getResultField("c", 1, 0)
118+
rf1 := getResultField("c1", 2, 1)
119+
ft := &types.FieldType{
120+
Tp: mysql.TypeString,
121+
Charset: charset.CharsetBin,
122+
Collate: charset.CollationBin,
123+
}
124+
ft1 := &types.FieldType{
125+
Tp: mysql.TypeString,
126+
Charset: charset.CharsetBin,
127+
Collate: charset.CollationBin,
128+
}
129+
130+
atomic.StoreInt32(&variable.EnableStmtSummary, 0)
131+
ck := chunk.NewChunkWithCapacity([]*types.FieldType{ft, ft1}, 1024)
132+
ck.AppendString(0, variable.TiDBEnableStmtSummary)
133+
ck.AppendString(1, "1")
134+
row := ck.GetRow(0)
135+
gvc.Update([]chunk.Row{row}, []*ast.ResultField{rf, rf1})
136+
c.Assert(atomic.LoadInt32(&variable.EnableStmtSummary), Equals, int32(1))
137+
138+
ck = chunk.NewChunkWithCapacity([]*types.FieldType{ft, ft1}, 1024)
139+
ck.AppendString(0, variable.TiDBEnableStmtSummary)
140+
ck.AppendString(1, "0")
141+
row = ck.GetRow(0)
142+
gvc.Update([]chunk.Row{row}, []*ast.ResultField{rf, rf1})
143+
c.Assert(atomic.LoadInt32(&variable.EnableStmtSummary), Equals, int32(0))
144+
}

executor/adapter.go

+23
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"github.com/pingcap/tidb/util/logutil"
4646
"github.com/pingcap/tidb/util/memory"
4747
"github.com/pingcap/tidb/util/sqlexec"
48+
"github.com/pingcap/tidb/util/stmtsummary"
4849
"go.uber.org/zap"
4950
"go.uber.org/zap/zapcore"
5051
)
@@ -135,6 +136,7 @@ func (a *recordSet) Close() error {
135136
a.stmt.LogSlowQuery(a.txnStartTS, a.lastErr == nil)
136137
a.stmt.Ctx.GetSessionVars().PrevStmt = a.stmt.OriginText()
137138
a.stmt.logAudit()
139+
a.stmt.SummaryStmt()
138140
return err
139141
}
140142

@@ -708,6 +710,27 @@ func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
708710
}
709711
}
710712

713+
// SummaryStmt collects statements for performance_schema.events_statements_summary_by_digest
714+
func (a *ExecStmt) SummaryStmt() {
715+
sessVars := a.Ctx.GetSessionVars()
716+
if sessVars.InRestrictedSQL || atomic.LoadInt32(&variable.EnableStmtSummary) == 0 {
717+
return
718+
}
719+
stmtCtx := sessVars.StmtCtx
720+
normalizedSQL, digest := stmtCtx.SQLDigest()
721+
costTime := time.Since(sessVars.StartTime)
722+
stmtsummary.StmtSummaryByDigestMap.AddStatement(&stmtsummary.StmtExecInfo{
723+
SchemaName: sessVars.CurrentDB,
724+
OriginalSQL: a.Text,
725+
NormalizedSQL: normalizedSQL,
726+
Digest: digest,
727+
TotalLatency: uint64(costTime.Nanoseconds()),
728+
AffectedRows: stmtCtx.AffectedRows(),
729+
SentRows: 0,
730+
StartTime: sessVars.StartTime,
731+
})
732+
}
733+
711734
// IsPointGetWithPKOrUniqueKeyByAutoCommit returns true when meets following conditions:
712735
// 1. ctx is auto commit tagged
713736
// 2. txn is not valid

infoschema/perfschema/const.go

+17
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ var perfSchemaTables = []string{
3636
tableStagesCurrent,
3737
tableStagesHistory,
3838
tableStagesHistoryLong,
39+
tableEventsStatementsSummaryByDigest,
3940
}
4041

4142
// tableGlobalStatus contains the column name definitions for table global_status, same as MySQL.
@@ -371,3 +372,19 @@ const tableStagesHistoryLong = "CREATE TABLE if not exists performance_schema.ev
371372
"WORK_ESTIMATED BIGINT(20) UNSIGNED," +
372373
"NESTING_EVENT_ID BIGINT(20) UNSIGNED," +
373374
"NESTING_EVENT_TYPE ENUM('TRANSACTION','STATEMENT','STAGE'));"
375+
376+
// tableEventsStatementsSummaryByDigest contains the column name definitions for table
377+
// events_statements_summary_by_digest, same as MySQL.
378+
const tableEventsStatementsSummaryByDigest = "CREATE TABLE if not exists events_statements_summary_by_digest (" +
379+
"SCHEMA_NAME VARCHAR(64) DEFAULT NULL," +
380+
"DIGEST VARCHAR(64) DEFAULT NULL," +
381+
"DIGEST_TEXT LONGTEXT DEFAULT NULL," +
382+
"EXEC_COUNT BIGINT(20) UNSIGNED NOT NULL," +
383+
"SUM_LATENCY BIGINT(20) UNSIGNED NOT NULL," +
384+
"MAX_LATENCY BIGINT(20) UNSIGNED NOT NULL," +
385+
"MIN_LATENCY BIGINT(20) UNSIGNED NOT NULL," +
386+
"AVG_LATENCY BIGINT(20) UNSIGNED NOT NULL," +
387+
"SUM_ROWS_AFFECTED BIGINT(20) UNSIGNED NOT NULL," +
388+
"FIRST_SEEN TIMESTAMP(6) NOT NULL," +
389+
"LAST_SEEN TIMESTAMP(6) NOT NULL," +
390+
"QUERY_SAMPLE_TEXT LONGTEXT DEFAULT NULL);"

infoschema/perfschema/tables.go

+49
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,16 @@ package perfschema
1616
import (
1717
"github.com/pingcap/parser/model"
1818
"github.com/pingcap/tidb/infoschema"
19+
"github.com/pingcap/tidb/kv"
1920
"github.com/pingcap/tidb/meta/autoid"
21+
"github.com/pingcap/tidb/sessionctx"
2022
"github.com/pingcap/tidb/table"
23+
"github.com/pingcap/tidb/types"
24+
"github.com/pingcap/tidb/util/stmtsummary"
25+
)
26+
27+
const (
28+
tableNameEventsStatementsSummaryByDigest = "events_statements_summary_by_digest"
2129
)
2230

2331
// perfSchemaTable stands for the fake table all its data is in the memory.
@@ -77,3 +85,44 @@ func (vt *perfSchemaTable) GetPhysicalID() int64 {
7785
func (vt *perfSchemaTable) Meta() *model.TableInfo {
7886
return vt.meta
7987
}
88+
89+
func (vt *perfSchemaTable) getRows(ctx sessionctx.Context, cols []*table.Column) (fullRows [][]types.Datum, err error) {
90+
switch vt.meta.Name.O {
91+
case tableNameEventsStatementsSummaryByDigest:
92+
fullRows = stmtsummary.StmtSummaryByDigestMap.ToDatum()
93+
}
94+
if len(cols) == len(vt.cols) {
95+
return
96+
}
97+
rows := make([][]types.Datum, len(fullRows))
98+
for i, fullRow := range fullRows {
99+
row := make([]types.Datum, len(cols))
100+
for j, col := range cols {
101+
row[j] = fullRow[col.Offset]
102+
}
103+
rows[i] = row
104+
}
105+
return rows, nil
106+
}
107+
108+
// IterRecords implements table.Table IterRecords interface.
109+
func (vt *perfSchemaTable) IterRecords(ctx sessionctx.Context, startKey kv.Key, cols []*table.Column,
110+
fn table.RecordIterFunc) error {
111+
if len(startKey) != 0 {
112+
return table.ErrUnsupportedOp
113+
}
114+
rows, err := vt.getRows(ctx, cols)
115+
if err != nil {
116+
return err
117+
}
118+
for i, row := range rows {
119+
more, err := fn(int64(i), row, cols)
120+
if err != nil {
121+
return err
122+
}
123+
if !more {
124+
break
125+
}
126+
}
127+
return nil
128+
}

0 commit comments

Comments
 (0)