Skip to content

Commit 36b2efc

Browse files
winorosti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#46138
Signed-off-by: ti-chi-bot <[email protected]>
1 parent cc04dd7 commit 36b2efc

File tree

8 files changed

+181
-7
lines changed

8 files changed

+181
-7
lines changed

build/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,13 @@ nogo(
150150
"//build/linter/revive",
151151
],
152152
"//conditions:default": [],
153+
<<<<<<< HEAD
154+
=======
155+
}) +
156+
select({
157+
"//build:without_rbe": [
158+
],
159+
"//conditions:default": [],
160+
>>>>>>> 51f1a828e47 (statistics: record last gc ts to avoid huge read on stats table (#46138))
153161
}),
154162
)

ddl/partition.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,13 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) (
19591959
return ver, errors.Trace(err)
19601960
}
19611961
}
1962+
<<<<<<< HEAD
1963+
=======
1964+
if tblInfo.TiFlashReplica != nil {
1965+
removeTiFlashAvailablePartitionIDs(tblInfo, physicalTableIDs)
1966+
}
1967+
droppedDefs := tblInfo.Partition.DroppingDefinitions
1968+
>>>>>>> 51f1a828e47 (statistics: record last gc ts to avoid huge read on stats table (#46138))
19621969
tblInfo.Partition.DroppingDefinitions = nil
19631970
// used by ApplyDiff in updateSchemaVersion
19641971
job.CtxVars = []interface{}{physicalTableIDs}
@@ -1968,7 +1975,7 @@ func (w *worker) onDropTablePartition(d *ddlCtx, t *meta.Meta, job *model.Job) (
19681975
}
19691976
job.SchemaState = model.StateNone
19701977
job.FinishTableJob(model.JobStateDone, model.StateNone, ver, tblInfo)
1971-
asyncNotifyEvent(d, &util.Event{Tp: model.ActionDropTablePartition, TableInfo: tblInfo, PartInfo: &model.PartitionInfo{Definitions: tblInfo.Partition.Definitions}})
1978+
asyncNotifyEvent(d, &util.Event{Tp: model.ActionDropTablePartition, TableInfo: tblInfo, PartInfo: &model.PartitionInfo{Definitions: droppedDefs}})
19721979
// A background job will be created to delete old partition data.
19731980
job.Args = []interface{}{physicalTableIDs}
19741981
default:

ddl/table.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ func onDropTableOrView(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ er
393393
job.FinishTableJob(model.JobStateDone, model.StateNone, ver, tblInfo)
394394
startKey := tablecodec.EncodeTablePrefix(job.TableID)
395395
job.Args = append(job.Args, startKey, oldIDs, ruleIDs)
396+
if tblInfo.IsSequence() {
397+
asyncNotifyEvent(d, &util.Event{Tp: model.ActionDropSequence, TableInfo: tblInfo})
398+
} else if !tblInfo.IsView() {
399+
asyncNotifyEvent(d, &util.Event{Tp: model.ActionDropTable, TableInfo: tblInfo})
400+
}
396401
default:
397402
return ver, errors.Trace(dbterror.ErrInvalidDDLState.GenWithStackByArgs("table", tblInfo.State))
398403
}

statistics/handle/ddl.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ func (h *Handle) HandleDDLEvent(t *util.Event) error {
4141
return err
4242
}
4343
}
44+
case model.ActionDropTable:
45+
ids := h.getInitStateTableIDs(t.TableInfo)
46+
for _, id := range ids {
47+
if err := h.resetTableStats2KVForDrop(id); err != nil {
48+
return err
49+
}
50+
}
4451
case model.ActionAddColumn, model.ActionModifyColumn:
4552
ids := h.getInitStateTableIDs(t.TableInfo)
4653
for _, id := range ids {
@@ -61,6 +68,11 @@ func (h *Handle) HandleDDLEvent(t *util.Event) error {
6168
return err
6269
}
6370
}
71+
for _, def := range t.PartInfo.Definitions {
72+
if err := h.resetTableStats2KVForDrop(def.ID); err != nil {
73+
return err
74+
}
75+
}
6476
case model.ActionReorganizePartition:
6577
for _, def := range t.PartInfo.Definitions {
6678
// TODO: Should we trigger analyze instead of adding 0s?
@@ -266,6 +278,36 @@ func (h *Handle) insertTableStats2KV(info *model.TableInfo, physicalID int64) (e
266278
return nil
267279
}
268280

281+
// resetTableStats2KV resets the count to 0.
282+
func (h *Handle) resetTableStats2KVForDrop(physicalID int64) (err error) {
283+
statsVer := uint64(0)
284+
defer func() {
285+
if err == nil && statsVer != 0 {
286+
h.recordHistoricalStatsMeta(physicalID, statsVer, StatsMetaHistorySourceSchemaChange)
287+
}
288+
}()
289+
h.mu.Lock()
290+
defer h.mu.Unlock()
291+
ctx := kv.WithInternalSourceType(context.Background(), kv.InternalTxnStats)
292+
exec := h.mu.ctx.(sqlexec.SQLExecutor)
293+
_, err = exec.ExecuteInternal(ctx, "begin")
294+
if err != nil {
295+
return errors.Trace(err)
296+
}
297+
defer func() {
298+
err = finishTransaction(ctx, exec, err)
299+
}()
300+
txn, err := h.mu.ctx.Txn(true)
301+
if err != nil {
302+
return errors.Trace(err)
303+
}
304+
startTS := txn.StartTS()
305+
if _, err := exec.ExecuteInternal(ctx, "update mysql.stats_meta set version=%? where table_id =%?", startTS, physicalID); err != nil {
306+
return err
307+
}
308+
return nil
309+
}
310+
269311
// insertColStats2KV insert a record to stats_histograms with distinct_count 1 and insert a bucket to stats_buckets with default value.
270312
// This operation also updates version.
271313
func (h *Handle) insertColStats2KV(physicalID int64, colInfos []*model.ColumnInfo) (err error) {

statistics/handle/ddl_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,16 @@ func TestDDLHistogram(t *testing.T) {
213213
func TestDDLPartition(t *testing.T) {
214214
store, do := testkit.CreateMockStoreAndDomain(t)
215215
testKit := testkit.NewTestKit(t, store)
216-
for _, pruneMode := range []string{"static", "dynamic"} {
216+
for i, pruneMode := range []string{"static", "dynamic"} {
217217
testKit.MustExec("set @@tidb_partition_prune_mode=`" + pruneMode + "`")
218218
testKit.MustExec("set global tidb_partition_prune_mode=`" + pruneMode + "`")
219219
testKit.MustExec("use test")
220220
testKit.MustExec("drop table if exists t")
221+
h := do.StatsHandle()
222+
if i == 1 {
223+
err := h.HandleDDLEvent(<-h.DDLEventCh())
224+
require.NoError(t, err)
225+
}
221226
createTable := `CREATE TABLE t (a int, b int, primary key(a), index idx(b))
222227
PARTITION BY RANGE ( a ) (
223228
PARTITION p0 VALUES LESS THAN (6),
@@ -230,14 +235,13 @@ PARTITION BY RANGE ( a ) (
230235
tbl, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
231236
require.NoError(t, err)
232237
tableInfo := tbl.Meta()
233-
h := do.StatsHandle()
234238
err = h.HandleDDLEvent(<-h.DDLEventCh())
235239
require.NoError(t, err)
236240
require.Nil(t, h.Update(is))
237241
pi := tableInfo.GetPartitionInfo()
238242
for _, def := range pi.Definitions {
239243
statsTbl := h.GetPartitionStats(tableInfo, def.ID)
240-
require.False(t, statsTbl.Pseudo)
244+
require.False(t, statsTbl.Pseudo, "for %v", pruneMode)
241245
}
242246

243247
testKit.MustExec("insert into t values (1,2),(6,2),(11,2),(16,2)")

statistics/handle/gc.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package handle
1717
import (
1818
"context"
1919
"encoding/json"
20+
"strconv"
2021
"time"
2122

2223
"github.com/pingcap/errors"
@@ -33,9 +34,11 @@ import (
3334
"go.uber.org/zap"
3435
)
3536

37+
const gcLastTSVarName = "tidb_stats_gc_last_ts"
38+
3639
// GCStats will garbage collect the useless stats info. For dropped tables, we will first update their version so that
3740
// other tidb could know that table is deleted.
38-
func (h *Handle) GCStats(is infoschema.InfoSchema, ddlLease time.Duration) error {
41+
func (h *Handle) GCStats(is infoschema.InfoSchema, ddlLease time.Duration) (err error) {
3942
ctx := context.Background()
4043
// To make sure that all the deleted tables' schema and stats info have been acknowledged to all tidb,
4144
// we only garbage collect version before 10 lease.
@@ -46,7 +49,17 @@ func (h *Handle) GCStats(is infoschema.InfoSchema, ddlLease time.Duration) error
4649
return nil
4750
}
4851
gcVer := now - offset
49-
rows, _, err := h.execRestrictedSQL(ctx, "select table_id from mysql.stats_meta where version < %?", gcVer)
52+
lastGC, err := h.GetLastGCTimestamp(ctx)
53+
if err != nil {
54+
return err
55+
}
56+
defer func() {
57+
if err != nil {
58+
return
59+
}
60+
err = h.writeGCTimestampToKV(ctx, gcVer)
61+
}()
62+
rows, _, err := h.execRestrictedSQL(ctx, "select table_id from mysql.stats_meta where version >= %? and version < %?", lastGC, gcVer)
5063
if err != nil {
5164
return errors.Trace(err)
5265
}
@@ -69,6 +82,33 @@ func (h *Handle) GCStats(is infoschema.InfoSchema, ddlLease time.Duration) error
6982
return h.removeDeletedExtendedStats(gcVer)
7083
}
7184

85+
// GetLastGCTimestamp loads the last gc time from mysql.tidb.
86+
func (h *Handle) GetLastGCTimestamp(ctx context.Context) (uint64, error) {
87+
rows, _, err := h.execRestrictedSQL(ctx, "SELECT HIGH_PRIORITY variable_value FROM mysql.tidb WHERE variable_name=%?", gcLastTSVarName)
88+
if err != nil {
89+
return 0, errors.Trace(err)
90+
}
91+
if len(rows) == 0 {
92+
return 0, nil
93+
}
94+
lastGcTSString := rows[0].GetString(0)
95+
lastGcTS, err := strconv.ParseUint(lastGcTSString, 10, 64)
96+
if err != nil {
97+
return 0, errors.Trace(err)
98+
}
99+
return lastGcTS, nil
100+
}
101+
102+
func (h *Handle) writeGCTimestampToKV(ctx context.Context, newTS uint64) error {
103+
_, _, err := h.execRestrictedSQL(ctx,
104+
"insert into mysql.tidb (variable_name, variable_value) values (%?, %?) on duplicate key update variable_value = %?",
105+
gcLastTSVarName,
106+
newTS,
107+
newTS,
108+
)
109+
return err
110+
}
111+
72112
func (h *Handle) gcTableStats(is infoschema.InfoSchema, physicalID int64) error {
73113
ctx := context.Background()
74114
rows, _, err := h.execRestrictedSQL(ctx, "select is_index, hist_id from mysql.stats_histograms where table_id = %?", physicalID)

statistics/handle/gc_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ func TestGCExtendedStats(t *testing.T) {
103103
testKit.MustExec("insert into t values (1,1,1),(2,2,2),(3,3,3)")
104104
testKit.MustExec("alter table t add stats_extended s1 correlation(a,b)")
105105
testKit.MustExec("alter table t add stats_extended s2 correlation(b,c)")
106+
h := dom.StatsHandle()
107+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
106108
testKit.MustExec("analyze table t")
107109

108110
testKit.MustQuery("select name, type, column_ids, stats, status from mysql.stats_extended").Sort().Check(testkit.Rows(
@@ -114,7 +116,6 @@ func TestGCExtendedStats(t *testing.T) {
114116
"s1 2 [1,2] 1.000000 1",
115117
"s2 2 [2,3] 1.000000 1",
116118
))
117-
h := dom.StatsHandle()
118119
ddlLease := time.Duration(0)
119120
require.Nil(t, h.GCStats(dom.InfoSchema(), ddlLease))
120121
testKit.MustQuery("select name, type, column_ids, stats, status from mysql.stats_extended").Sort().Check(testkit.Rows(
@@ -130,6 +131,7 @@ func TestGCExtendedStats(t *testing.T) {
130131
testKit.MustQuery("select name, type, column_ids, stats, status from mysql.stats_extended").Sort().Check(testkit.Rows(
131132
"s2 2 [2,3] 1.000000 1",
132133
))
134+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
133135
require.Nil(t, h.GCStats(dom.InfoSchema(), ddlLease))
134136
testKit.MustQuery("select name, type, column_ids, stats, status from mysql.stats_extended").Sort().Check(testkit.Rows(
135137
"s2 2 [2,3] 1.000000 2",

statistics/integration_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ func TestIssue49986(t *testing.T) {
913913
tk := testkit.NewTestKit(t, store)
914914
tk.MustExec("use test")
915915

916+
<<<<<<< HEAD
916917
tk.MustExec("drop table if exists test.t;")
917918
tk.MustExec("create table if not exists test.ast (i varchar(20));")
918919
tk.MustExec("create table if not exists test.acc (j varchar(20), k varchar(20), l varchar(20), m varchar(20));")
@@ -927,4 +928,69 @@ func TestIssue49986(t *testing.T) {
927928
" └─TableReader(Probe) 10.00 root data:Selection",
928929
" └─Selection 10.00 cop[tikv] eq(\"astp2019121731703151\", test.acc.m)",
929930
" └─TableFullScan 10000.00 cop[tikv] table:b keep order:false, stats:pseudo"))
931+
=======
932+
for i, version := range []string{"1", "2"} {
933+
tk.MustExec("set @@session.tidb_analyze_version = " + version)
934+
935+
// analyze table t
936+
tk.MustExec("drop table if exists t")
937+
if i != 0 {
938+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
939+
}
940+
tk.MustExec("CREATE TABLE t ( a int, b int, c int default 0, key(a) )" +
941+
"PARTITION BY RANGE (a) (" +
942+
"PARTITION p0 VALUES LESS THAN (10)," +
943+
"PARTITION p1 VALUES LESS THAN (20)," +
944+
"PARTITION p2 VALUES LESS THAN (30)," +
945+
"PARTITION p3 VALUES LESS THAN (40))")
946+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
947+
tk.MustExec("insert into t(a,b) values (1,1), (2,2), (3,3), (15,15), (25,25), (35,35)")
948+
tk.MustExec("ALTER TABLE t ADD UNIQUE INDEX idx(b)")
949+
require.Nil(t, h.DumpStatsDeltaToKV(handle.DumpAll))
950+
tk.MustExec("analyze table t")
951+
require.Nil(t, h.Update(dom.InfoSchema()))
952+
tk.MustQuery("SELECT b FROM t use index(idx) WHERE b < 16 ORDER BY b").
953+
Check(testkit.Rows("1", "2", "3", "15"))
954+
tk.MustQuery("EXPLAIN SELECT b FROM t use index(idx) WHERE b < 16 ORDER BY b").
955+
Check(testkit.Rows("IndexReader_12 4.00 root partition:all index:IndexRangeScan_11",
956+
"└─IndexRangeScan_11 4.00 cop[tikv] table:t, index:idx(b) range:[-inf,16), keep order:true"))
957+
958+
// analyze table t index idx
959+
tk.MustExec("drop table if exists t")
960+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
961+
tk.MustExec("CREATE TABLE t ( a int, b int, c int default 0, primary key(b, a) clustered )" +
962+
"PARTITION BY RANGE (a) (" +
963+
"PARTITION p0 VALUES LESS THAN (10)," +
964+
"PARTITION p1 VALUES LESS THAN (20)," +
965+
"PARTITION p2 VALUES LESS THAN (30)," +
966+
"PARTITION p3 VALUES LESS THAN (40));")
967+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
968+
tk.MustExec("insert into t(a,b) values (1,1), (2,2), (3,3), (15,15), (25,25), (35,35)")
969+
tk.MustExec("ALTER TABLE t ADD UNIQUE INDEX idx(b);")
970+
require.Nil(t, h.DumpStatsDeltaToKV(handle.DumpAll))
971+
tk.MustExec("analyze table t index idx")
972+
require.Nil(t, h.Update(dom.InfoSchema()))
973+
rows := tk.MustQuery("EXPLAIN SELECT b FROM t use index(idx) WHERE b < 16 ORDER BY b;").Rows()
974+
require.Equal(t, "4.00", rows[0][1])
975+
976+
// analyze table t index
977+
tk.MustExec("drop table if exists t")
978+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
979+
tk.MustExec("CREATE TABLE t ( a int, b int, c int default 0, primary key(b, a) clustered )" +
980+
"PARTITION BY RANGE (a) (" +
981+
"PARTITION p0 VALUES LESS THAN (10)," +
982+
"PARTITION p1 VALUES LESS THAN (20)," +
983+
"PARTITION p2 VALUES LESS THAN (30)," +
984+
"PARTITION p3 VALUES LESS THAN (40));")
985+
require.Nil(t, h.HandleDDLEvent(<-h.DDLEventCh()))
986+
tk.MustExec("insert into t(a,b) values (1,1), (2,2), (3,3), (15,15), (25,25), (35,35)")
987+
tk.MustExec("ALTER TABLE t ADD UNIQUE INDEX idx(b);")
988+
require.Nil(t, h.DumpStatsDeltaToKV(handle.DumpAll))
989+
tk.MustExec("analyze table t index")
990+
require.Nil(t, h.Update(dom.InfoSchema()))
991+
tk.MustQuery("EXPLAIN SELECT b FROM t use index(idx) WHERE b < 16 ORDER BY b;").
992+
Check(testkit.Rows("IndexReader_12 4.00 root partition:all index:IndexRangeScan_11",
993+
"└─IndexRangeScan_11 4.00 cop[tikv] table:t, index:idx(b) range:[-inf,16), keep order:true"))
994+
}
995+
>>>>>>> 51f1a828e47 (statistics: record last gc ts to avoid huge read on stats table (#46138))
930996
}

0 commit comments

Comments
 (0)