Skip to content

Commit cc1da16

Browse files
authored
stats: support show stats for partition table (#8023)
1 parent b87b5f0 commit cc1da16

File tree

4 files changed

+143
-63
lines changed

4 files changed

+143
-63
lines changed

executor/show_stats.go

+92-43
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,69 @@ func (e *ShowExec) fetchShowStatsMeta() error {
3030
dbs := do.InfoSchema().AllSchemas()
3131
for _, db := range dbs {
3232
for _, tbl := range db.Tables {
33-
statsTbl := h.GetTableStats(tbl)
34-
if !statsTbl.Pseudo {
35-
e.appendRow([]interface{}{
36-
db.Name.O,
37-
tbl.Name.O,
38-
e.versionToTime(statsTbl.Version),
39-
statsTbl.ModifyCount,
40-
statsTbl.Count,
41-
})
33+
pi := tbl.GetPartitionInfo()
34+
if pi == nil {
35+
e.appendTableForStatsMeta(db.Name.O, tbl.Name.O, "", h.GetTableStats(tbl))
36+
} else {
37+
for _, def := range pi.Definitions {
38+
e.appendTableForStatsMeta(db.Name.O, tbl.Name.O, def.Name.O, h.GetPartitionStats(tbl, def.ID))
39+
}
4240
}
4341
}
4442
}
4543
return nil
4644
}
4745

46+
func (e *ShowExec) appendTableForStatsMeta(dbName, tblName, partitionName string, statsTbl *statistics.Table) {
47+
if statsTbl.Pseudo {
48+
return
49+
}
50+
e.appendRow([]interface{}{
51+
dbName,
52+
tblName,
53+
partitionName,
54+
e.versionToTime(statsTbl.Version),
55+
statsTbl.ModifyCount,
56+
statsTbl.Count,
57+
})
58+
}
59+
4860
func (e *ShowExec) fetchShowStatsHistogram() error {
4961
do := domain.GetDomain(e.ctx)
5062
h := do.StatsHandle()
5163
dbs := do.InfoSchema().AllSchemas()
5264
for _, db := range dbs {
5365
for _, tbl := range db.Tables {
54-
statsTbl := h.GetTableStats(tbl)
55-
if !statsTbl.Pseudo {
56-
for _, col := range statsTbl.Columns {
57-
e.histogramToRow(db.Name.O, tbl.Name.O, col.Info.Name.O, 0, col.Histogram, col.AvgColSize(statsTbl.Count))
58-
}
59-
for _, idx := range statsTbl.Indices {
60-
e.histogramToRow(db.Name.O, tbl.Name.O, idx.Info.Name.O, 1, idx.Histogram, 0)
66+
pi := tbl.GetPartitionInfo()
67+
if pi == nil {
68+
e.appendTableForStatsHistograms(db.Name.O, tbl.Name.O, "", h.GetTableStats(tbl))
69+
} else {
70+
for _, def := range pi.Definitions {
71+
e.appendTableForStatsHistograms(db.Name.O, tbl.Name.O, def.Name.O, h.GetPartitionStats(tbl, def.ID))
6172
}
6273
}
6374
}
6475
}
6576
return nil
6677
}
6778

68-
func (e *ShowExec) histogramToRow(dbName string, tblName string, colName string, isIndex int, hist statistics.Histogram, avgColSize float64) {
79+
func (e *ShowExec) appendTableForStatsHistograms(dbName, tblName, partitionName string, statsTbl *statistics.Table) {
80+
if statsTbl.Pseudo {
81+
return
82+
}
83+
for _, col := range statsTbl.Columns {
84+
e.histogramToRow(dbName, tblName, partitionName, col.Info.Name.O, 0, col.Histogram, col.AvgColSize(statsTbl.Count))
85+
}
86+
for _, idx := range statsTbl.Indices {
87+
e.histogramToRow(dbName, tblName, partitionName, idx.Info.Name.O, 1, idx.Histogram, 0)
88+
}
89+
}
90+
91+
func (e *ShowExec) histogramToRow(dbName, tblName, partitionName, colName string, isIndex int, hist statistics.Histogram, avgColSize float64) {
6992
e.appendRow([]interface{}{
7093
dbName,
7194
tblName,
95+
partitionName,
7296
colName,
7397
isIndex,
7498
e.versionToTime(hist.LastUpdateVersion),
@@ -89,29 +113,41 @@ func (e *ShowExec) fetchShowStatsBuckets() error {
89113
dbs := do.InfoSchema().AllSchemas()
90114
for _, db := range dbs {
91115
for _, tbl := range db.Tables {
92-
statsTbl := h.GetTableStats(tbl)
93-
if !statsTbl.Pseudo {
94-
for _, col := range statsTbl.Columns {
95-
err := e.bucketsToRows(db.Name.O, tbl.Name.O, col.Info.Name.O, 0, col.Histogram)
96-
if err != nil {
97-
return errors.Trace(err)
98-
}
99-
}
100-
for _, idx := range statsTbl.Indices {
101-
err := e.bucketsToRows(db.Name.O, tbl.Name.O, idx.Info.Name.O, len(idx.Info.Columns), idx.Histogram)
102-
if err != nil {
103-
return errors.Trace(err)
104-
}
116+
pi := tbl.GetPartitionInfo()
117+
if pi == nil {
118+
e.appendTableForStatsBuckets(db.Name.O, tbl.Name.O, "", h.GetTableStats(tbl))
119+
} else {
120+
for _, def := range pi.Definitions {
121+
e.appendTableForStatsBuckets(db.Name.O, tbl.Name.O, def.Name.O, h.GetPartitionStats(tbl, def.ID))
105122
}
106123
}
107124
}
108125
}
109126
return nil
110127
}
111128

129+
func (e *ShowExec) appendTableForStatsBuckets(dbName, tblName, partitionName string, statsTbl *statistics.Table) error {
130+
if statsTbl.Pseudo {
131+
return nil
132+
}
133+
for _, col := range statsTbl.Columns {
134+
err := e.bucketsToRows(dbName, tblName, partitionName, col.Info.Name.O, 0, col.Histogram)
135+
if err != nil {
136+
return errors.Trace(err)
137+
}
138+
}
139+
for _, idx := range statsTbl.Indices {
140+
err := e.bucketsToRows(dbName, tblName, partitionName, idx.Info.Name.O, len(idx.Info.Columns), idx.Histogram)
141+
if err != nil {
142+
return errors.Trace(err)
143+
}
144+
}
145+
return nil
146+
}
147+
112148
// bucketsToRows converts histogram buckets to rows. If the histogram is built from index, then numOfCols equals to number
113149
// of index columns, else numOfCols is 0.
114-
func (e *ShowExec) bucketsToRows(dbName, tblName, colName string, numOfCols int, hist statistics.Histogram) error {
150+
func (e *ShowExec) bucketsToRows(dbName, tblName, partitionName, colName string, numOfCols int, hist statistics.Histogram) error {
115151
isIndex := 0
116152
if numOfCols > 0 {
117153
isIndex = 1
@@ -128,6 +164,7 @@ func (e *ShowExec) bucketsToRows(dbName, tblName, colName string, numOfCols int,
128164
e.appendRow([]interface{}{
129165
dbName,
130166
tblName,
167+
partitionName,
131168
colName,
132169
isIndex,
133170
i,
@@ -146,20 +183,32 @@ func (e *ShowExec) fetchShowStatsHealthy() {
146183
dbs := do.InfoSchema().AllSchemas()
147184
for _, db := range dbs {
148185
for _, tbl := range db.Tables {
149-
statsTbl := h.GetTableStats(tbl)
150-
if !statsTbl.Pseudo {
151-
var healthy int64
152-
if statsTbl.ModifyCount < statsTbl.Count {
153-
healthy = int64((1.0 - float64(statsTbl.ModifyCount)/float64(statsTbl.Count)) * 100.0)
154-
} else if statsTbl.ModifyCount == 0 {
155-
healthy = 100
186+
pi := tbl.GetPartitionInfo()
187+
if pi == nil {
188+
e.appendTableForStatsHealthy(db.Name.O, tbl.Name.O, "", h.GetTableStats(tbl))
189+
} else {
190+
for _, def := range pi.Definitions {
191+
e.appendTableForStatsHealthy(db.Name.O, tbl.Name.O, def.Name.O, h.GetPartitionStats(tbl, def.ID))
156192
}
157-
e.appendRow([]interface{}{
158-
db.Name.O,
159-
tbl.Name.O,
160-
healthy,
161-
})
162193
}
163194
}
164195
}
165196
}
197+
198+
func (e *ShowExec) appendTableForStatsHealthy(dbName, tblName, partitionName string, statsTbl *statistics.Table) {
199+
if statsTbl.Pseudo {
200+
return
201+
}
202+
var healthy int64
203+
if statsTbl.ModifyCount < statsTbl.Count {
204+
healthy = int64((1.0 - float64(statsTbl.ModifyCount)/float64(statsTbl.Count)) * 100.0)
205+
} else if statsTbl.ModifyCount == 0 {
206+
healthy = 100
207+
}
208+
e.appendRow([]interface{}{
209+
dbName,
210+
tblName,
211+
partitionName,
212+
healthy,
213+
})
214+
}

executor/show_stats_test.go

+42-11
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ func (s *testSuite) TestShowStatsHistograms(c *C) {
4444
tk.MustExec("analyze table t")
4545
result := tk.MustQuery("show stats_histograms").Sort()
4646
c.Assert(len(result.Rows()), Equals, 2)
47-
c.Assert(result.Rows()[0][2], Equals, "a")
48-
c.Assert(result.Rows()[1][2], Equals, "b")
47+
c.Assert(result.Rows()[0][3], Equals, "a")
48+
c.Assert(result.Rows()[1][3], Equals, "b")
4949
result = tk.MustQuery("show stats_histograms where column_name = 'a'")
5050
c.Assert(len(result.Rows()), Equals, 1)
51-
c.Assert(result.Rows()[0][2], Equals, "a")
51+
c.Assert(result.Rows()[0][3], Equals, "a")
5252
}
5353

5454
func (s *testSuite) TestShowStatsBuckets(c *C) {
@@ -60,9 +60,9 @@ func (s *testSuite) TestShowStatsBuckets(c *C) {
6060
tk.MustExec("insert into t values (1,1)")
6161
tk.MustExec("analyze table t")
6262
result := tk.MustQuery("show stats_buckets").Sort()
63-
result.Sort().Check(testkit.Rows("test t a 0 0 1 1 1 1", "test t b 0 0 1 1 1 1", "test t idx 1 0 1 1 (1, 1) (1, 1)"))
63+
result.Check(testkit.Rows("test t a 0 0 1 1 1 1", "test t b 0 0 1 1 1 1", "test t idx 1 0 1 1 (1, 1) (1, 1)"))
6464
result = tk.MustQuery("show stats_buckets where column_name = 'idx'")
65-
result.Check(testkit.Rows("test t idx 1 0 1 1 (1, 1) (1, 1)"))
65+
result.Check(testkit.Rows("test t idx 1 0 1 1 (1, 1) (1, 1)"))
6666
}
6767

6868
func (s *testSuite) TestShowStatsHealthy(c *C) {
@@ -72,22 +72,22 @@ func (s *testSuite) TestShowStatsHealthy(c *C) {
7272
tk.MustExec("create table t (a int)")
7373
tk.MustExec("create index idx on t(a)")
7474
tk.MustExec("analyze table t")
75-
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
75+
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
7676
tk.MustExec("insert into t values (1), (2)")
7777
do, _ := session.GetDomain(s.store)
7878
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
7979
tk.MustExec("analyze table t")
80-
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
80+
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
8181
tk.MustExec("insert into t values (3), (4), (5), (6), (7), (8), (9), (10)")
8282
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
8383
do.StatsHandle().Update(do.InfoSchema())
84-
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 19"))
84+
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 19"))
8585
tk.MustExec("analyze table t")
86-
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
86+
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
8787
tk.MustExec("delete from t")
8888
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
8989
do.StatsHandle().Update(do.InfoSchema())
90-
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 0"))
90+
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 0"))
9191
}
9292

9393
func (s *testSuite) TestShowStatsHasNullValue(c *C) {
@@ -96,5 +96,36 @@ func (s *testSuite) TestShowStatsHasNullValue(c *C) {
9696
tk.MustExec("create table t (a int, index idx(a))")
9797
tk.MustExec("insert into t values(NULL)")
9898
tk.MustExec("analyze table t")
99-
tk.MustQuery("show stats_buckets").Check(testkit.Rows("test t idx 1 0 1 1 NULL NULL"))
99+
tk.MustQuery("show stats_buckets").Check(testkit.Rows("test t idx 1 0 1 1 NULL NULL"))
100+
}
101+
102+
func (s *testSuite) TestShowPartitionStats(c *C) {
103+
tk := testkit.NewTestKit(c, s.store)
104+
tk.MustExec("set @@session.tidb_enable_table_partition=1")
105+
tk.MustExec("use test")
106+
tk.MustExec("drop table if exists t")
107+
createTable := `CREATE TABLE t (a int, b int, primary key(a), index idx(b))
108+
PARTITION BY RANGE ( a ) (PARTITION p0 VALUES LESS THAN (6))`
109+
tk.MustExec(createTable)
110+
tk.MustExec(`insert into t values (1, 1)`)
111+
tk.MustExec("analyze table t")
112+
113+
result := tk.MustQuery("show stats_meta")
114+
c.Assert(len(result.Rows()), Equals, 1)
115+
c.Assert(result.Rows()[0][0], Equals, "test")
116+
c.Assert(result.Rows()[0][1], Equals, "t")
117+
c.Assert(result.Rows()[0][2], Equals, "p0")
118+
119+
result = tk.MustQuery("show stats_histograms").Sort()
120+
c.Assert(len(result.Rows()), Equals, 2)
121+
c.Assert(result.Rows()[0][2], Equals, "p0")
122+
c.Assert(result.Rows()[0][3], Equals, "a")
123+
c.Assert(result.Rows()[1][2], Equals, "p0")
124+
c.Assert(result.Rows()[1][3], Equals, "idx")
125+
126+
result = tk.MustQuery("show stats_buckets").Sort()
127+
result.Check(testkit.Rows("test t p0 a 0 0 1 1 1 1", "test t p0 idx 1 0 1 1 1 1"))
128+
129+
result = tk.MustQuery("show stats_healthy")
130+
result.Check(testkit.Rows("test t p0 100"))
100131
}

planner/core/planbuilder.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -1633,20 +1633,20 @@ func buildShowSchema(s *ast.ShowStmt) (schema *expression.Schema) {
16331633
ftypes = []byte{mysql.TypeLonglong, mysql.TypeVarchar, mysql.TypeVarchar,
16341634
mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeLong, mysql.TypeVarchar, mysql.TypeString, mysql.TypeLonglong}
16351635
case ast.ShowStatsMeta:
1636-
names = []string{"Db_name", "Table_name", "Update_time", "Modify_count", "Row_count"}
1637-
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeDatetime, mysql.TypeLonglong, mysql.TypeLonglong}
1636+
names = []string{"Db_name", "Table_name", "Partition_name", "Update_time", "Modify_count", "Row_count"}
1637+
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeDatetime, mysql.TypeLonglong, mysql.TypeLonglong}
16381638
case ast.ShowStatsHistograms:
1639-
names = []string{"Db_name", "Table_name", "Column_name", "Is_index", "Update_time", "Distinct_count", "Null_count", "Avg_col_size"}
1640-
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeTiny, mysql.TypeDatetime,
1639+
names = []string{"Db_name", "Table_name", "Partition_name", "Column_name", "Is_index", "Update_time", "Distinct_count", "Null_count", "Avg_col_size"}
1640+
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeTiny, mysql.TypeDatetime,
16411641
mysql.TypeLonglong, mysql.TypeLonglong, mysql.TypeDouble}
16421642
case ast.ShowStatsBuckets:
1643-
names = []string{"Db_name", "Table_name", "Column_name", "Is_index", "Bucket_id", "Count",
1643+
names = []string{"Db_name", "Table_name", "Partition_name", "Column_name", "Is_index", "Bucket_id", "Count",
16441644
"Repeats", "Lower_Bound", "Upper_Bound"}
1645-
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeTiny, mysql.TypeLonglong,
1645+
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeTiny, mysql.TypeLonglong,
16461646
mysql.TypeLonglong, mysql.TypeLonglong, mysql.TypeVarchar, mysql.TypeVarchar}
16471647
case ast.ShowStatsHealthy:
1648-
names = []string{"Db_name", "Table_name", "Healthy"}
1649-
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeLonglong}
1648+
names = []string{"Db_name", "Table_name", "Partition_name", "Healthy"}
1649+
ftypes = []byte{mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeVarchar, mysql.TypeLonglong}
16501650
case ast.ShowProfiles: // ShowProfiles is deprecated.
16511651
names = []string{"Query_ID", "Duration", "Query"}
16521652
ftypes = []byte{mysql.TypeLong, mysql.TypeDouble, mysql.TypeVarchar}

server/statistics_handler_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func (ds *testDumpStatsSuite) checkData(c *C, path string) {
153153
var dbName, tableName string
154154
var modifyCount, count int64
155155
var other interface{}
156-
err = rows.Scan(&dbName, &tableName, &other, &modifyCount, &count)
156+
err = rows.Scan(&dbName, &tableName, &other, &other, &modifyCount, &count)
157157
dbt.Check(err, IsNil)
158158
dbt.Check(dbName, Equals, "tidb")
159159
dbt.Check(tableName, Equals, "test")

0 commit comments

Comments
 (0)