stats: refine stats delta update (#6808)

This commit is contained in:
Haibin Xie
2018-06-26 13:51:23 +08:00
committed by Zhang Jian
parent c562bfff6f
commit 0fbb980f9b
12 changed files with 147 additions and 48 deletions

View File

@ -660,6 +660,7 @@ func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager)
log.Debug("[stats] update stats info fail: ", errors.ErrorStack(err))
}
case <-do.exit:
statsHandle.FlushStats()
do.wg.Done()
return
// This channel is sent only by ddl owner or the drop stats executor.
@ -681,7 +682,7 @@ func (do *Domain) updateStatsWorker(ctx sessionctx.Context, owner owner.Manager)
log.Debug("[stats] save meta to storage fail: ", errors.ErrorStack(err))
}
case <-deltaUpdateTicker.C:
err = statsHandle.DumpStatsDeltaToKV()
err = statsHandle.DumpStatsDeltaToKV(statistics.DumpDelta)
if err != nil {
log.Debug("[stats] dump stats delta fail: ", errors.ErrorStack(err))
}

View File

@ -16,6 +16,7 @@ package executor_test
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/util/testkit"
)
@ -74,17 +75,17 @@ func (s *testSuite) TestShowStatsHealthy(c *C) {
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
tk.MustExec("insert into t values (1), (2)")
do, _ := session.GetDomain(s.store)
do.StatsHandle().DumpStatsDeltaToKV()
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
tk.MustExec("analyze table t")
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
tk.MustExec("insert into t values (3), (4), (5), (6), (7), (8), (9), (10)")
do.StatsHandle().DumpStatsDeltaToKV()
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
do.StatsHandle().Update(do.InfoSchema())
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 19"))
tk.MustExec("analyze table t")
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 100"))
tk.MustExec("delete from t")
do.StatsHandle().DumpStatsDeltaToKV()
do.StatsHandle().DumpStatsDeltaToKV(statistics.DumpAll)
do.StatsHandle().Update(do.InfoSchema())
tk.MustQuery("show stats_healthy").Check(testkit.Rows("test t 0"))
}

View File

@ -16,6 +16,7 @@ package infoschema_test
import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/store/mockstore"
"github.com/pingcap/tidb/util/auth"
"github.com/pingcap/tidb/util/testkit"
@ -42,22 +43,22 @@ func (s *testSuite) TestDataForTableRowsCountField(c *C) {
tk.MustQuery("select table_rows from information_schema.tables where table_name='t'").Check(
testkit.Rows("0"))
tk.MustExec("insert into t(c, d) values(1, 2), (2, 3), (3, 4)")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
tk.MustQuery("select table_rows from information_schema.tables where table_name='t'").Check(
testkit.Rows("3"))
tk.MustExec("insert into t(c, d) values(4, 5)")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
tk.MustQuery("select table_rows from information_schema.tables where table_name='t'").Check(
testkit.Rows("4"))
tk.MustExec("delete from t where c >= 3")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
tk.MustQuery("select table_rows from information_schema.tables where table_name='t'").Check(
testkit.Rows("2"))
tk.MustExec("delete from t where c=3")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
tk.MustQuery("select table_rows from information_schema.tables where table_name='t'").Check(
testkit.Rows("2"))

View File

@ -25,6 +25,7 @@ import (
"github.com/pingcap/tidb/plan"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/store/mockstore"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"
@ -53,7 +54,7 @@ func (s *testAnalyzeSuite) TestCBOWithoutAnalyze(c *C) {
c.Assert(h.HandleDDLEvent(<-h.DDLEventCh()), IsNil)
testKit.MustExec("insert into t1 values (1), (2), (3), (4), (5), (6)")
testKit.MustExec("insert into t2 values (1), (2), (3), (4), (5), (6)")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
c.Assert(h.Update(dom.InfoSchema()), IsNil)
testKit.MustQuery("explain select * from t1, t2 where t1.a = t2.a").Check(testkit.Rows(
"TableScan_10 cop table:t1, range:[-inf,+inf], keep order:false 6.00",
@ -139,7 +140,7 @@ func (s *testAnalyzeSuite) TestTableDual(c *C) {
testKit.MustExec("insert into t values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)")
c.Assert(h.HandleDDLEvent(<-h.DDLEventCh()), IsNil)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
c.Assert(h.Update(dom.InfoSchema()), IsNil)
testKit.MustQuery(`explain select * from t where 1 = 0`).Check(testkit.Rows(
@ -170,12 +171,12 @@ func (s *testAnalyzeSuite) TestEstimation(c *C) {
testKit.MustExec("insert into t select * from t")
h := dom.StatsHandle()
h.HandleDDLEvent(<-h.DDLEventCh())
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
testKit.MustExec("analyze table t")
for i := 1; i <= 8; i++ {
testKit.MustExec("delete from t where a = ?", i)
}
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
c.Assert(h.Update(dom.InfoSchema()), IsNil)
testKit.MustQuery("explain select count(*) from t group by a").Check(testkit.Rows(
"TableScan_8 HashAgg_5 cop table:t, range:[-inf,+inf], keep order:false 8.00",
@ -486,12 +487,12 @@ func (s *testAnalyzeSuite) TestOutdatedAnalyze(c *C) {
}
h := dom.StatsHandle()
h.HandleDDLEvent(<-h.DDLEventCh())
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
testKit.MustExec("analyze table t")
testKit.MustExec("insert into t select * from t")
testKit.MustExec("insert into t select * from t")
testKit.MustExec("insert into t select * from t")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
c.Assert(h.Update(dom.InfoSchema()), IsNil)
plan.RatioOfPseudoEstimate = 10.0
testKit.MustQuery("explain select * from t where a <= 5 and b <= 5").Check(testkit.Rows(

View File

@ -27,6 +27,7 @@ import (
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/store/mockstore"
"github.com/pingcap/tidb/store/mockstore/mocktikv"
)
@ -118,11 +119,11 @@ func (ds *testDumpStatsSuite) prepareData(c *C) {
h.HandleDDLEvent(<-h.DDLEventCh())
dbt.mustExec("create index c on test (a, b)")
dbt.mustExec("insert test values (1, 's')")
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
dbt.mustExec("analyze table test")
dbt.mustExec("insert into test(a,b) values (1, 'v'),(3, 'vvv'),(5, 'vv')")
is := ds.sh.do.InfoSchema()
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
c.Assert(h.Update(is), IsNil)
}

View File

@ -561,9 +561,10 @@ const (
// TableDelta stands for the changed count for one table.
type TableDelta struct {
Delta int64
Count int64
ColSize map[int64]int64
Delta int64
Count int64
ColSize map[int64]int64
InitTime time.Time // InitTime is the time that this delta is generated.
}
// Concurrency defines concurrency values.

View File

@ -18,6 +18,7 @@ import (
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/model"
"github.com/pingcap/tidb/statistics"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"
)
@ -54,7 +55,7 @@ func (s *testDumpStatsSuite) TestConversion(c *C) {
tk.MustExec("insert into t(a,b) values (1, 1),(3, 1),(5, 10)")
is := s.do.InfoSchema()
h := s.do.StatsHandle()
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
tableInfo, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))

View File

@ -214,3 +214,27 @@ func (h *Handle) LoadNeededHistograms() error {
func (h *Handle) LoadMetaCh() chan *LoadMeta {
return h.loadMetaCh
}
// FlushStats flushes the cached stats update into store.
func (h *Handle) FlushStats() {
for len(h.ddlEventCh) > 0 {
e := <-h.ddlEventCh
if err := h.HandleDDLEvent(e); err != nil {
log.Debug("[stats] handle ddl event fail: ", errors.ErrorStack(err))
}
}
if err := h.DumpStatsDeltaToKV(DumpAll); err != nil {
log.Debug("[stats] dump stats delta fail: ", errors.ErrorStack(err))
}
for len(h.analyzeResultCh) > 0 {
t := <-h.analyzeResultCh
for i, hg := range t.Hist {
if err := SaveStatsToStorage(h.ctx, t.TableID, t.Count, t.IsIndex, hg, t.Cms[i]); err != nil {
log.Debug("[stats] save histogram to storage fail: ", errors.ErrorStack(err))
}
}
}
if err := h.DumpStatsFeedbackToKV(); err != nil {
log.Debug("[stats] dump stats feedback fail: ", errors.ErrorStack(err))
}
}

View File

@ -339,7 +339,7 @@ func (s *testStatsCacheSuite) TestLoadHist(c *C) {
for i := 0; i < rowCount; i++ {
testKit.MustExec("insert into t values('bb','sdfga')")
}
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(do.InfoSchema())
newStatsTbl := h.GetTableStats(tableInfo)
// The stats table is updated.

View File

@ -156,15 +156,56 @@ func (h *Handle) NewSessionStatsCollector() *SessionStatsCollector {
return newCollector
}
// DumpStatsDeltaToKV sweeps the whole list and updates the global map. Then we dumps every table that held in map to KV.
func (h *Handle) DumpStatsDeltaToKV() error {
var (
// DumpStatsDeltaRatio is the lower bound of `Modify Count / Table Count` for stats delta to be dumped.
DumpStatsDeltaRatio = 1 / 10000.0
// dumpStatsMaxDuration is the max duration since last update.
dumpStatsMaxDuration = time.Hour
)
// needDumpStatsDelta returns true when only updates a small portion of the table and the time since last update
// do not exceed one hour.
func needDumpStatsDelta(h *Handle, id int64, item variable.TableDelta, currentTime time.Time) bool {
if item.InitTime.IsZero() {
item.InitTime = currentTime
}
tbl, ok := h.statsCache.Load().(statsCache)[id]
if !ok {
// No need to dump if the stats is invalid.
return false
}
if currentTime.Sub(item.InitTime) > dumpStatsMaxDuration {
// Dump the stats to kv at least once an hour.
return true
}
if tbl.Count == 0 || float64(item.Count)/float64(tbl.Count) > DumpStatsDeltaRatio {
// Dump the stats when there are many modifications.
return true
}
return false
}
const (
// DumpAll indicates dump all the delta info in to kv
DumpAll = true
// DumpDelta indicates dump part of the delta info in to kv.
DumpDelta = false
)
// DumpStatsDeltaToKV sweeps the whole list and updates the global map, then we dumps every table that held in map to KV.
// If the `dumpAll` is false, it will only dump that delta info that `Modify Count / Table Count` greater than a ratio.
func (h *Handle) DumpStatsDeltaToKV(dumpMode bool) error {
h.listHead.Lock()
for collector := h.listHead.next; collector != nil; collector = collector.next {
collector.tryToRemoveFromList()
h.merge(collector)
}
h.listHead.Unlock()
currentTime := time.Now()
for id, item := range h.globalMap {
if dumpMode == DumpDelta && !needDumpStatsDelta(h, id, item, currentTime) {
continue
}
updated, err := h.dumpTableStatCountToKV(id, item)
if err != nil {
return errors.Trace(err)

View File

@ -31,7 +31,7 @@ func (s *testUpdateListSuite) TestInsertAndDelete(c *C) {
items[0].Delete() // delete tail
items[2].Delete() // delete middle
items[4].Delete() // delete head
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(DumpAll)
c.Assert(h.listHead.next, Equals, items[3])
c.Assert(items[3].next, Equals, items[1])
@ -42,6 +42,6 @@ func (s *testUpdateListSuite) TestInsertAndDelete(c *C) {
// delete rest
items[1].Delete()
items[3].Delete()
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(DumpAll)
c.Assert(h.listHead.next, IsNil)
}

View File

@ -75,7 +75,7 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
h.HandleDDLEvent(<-h.DDLEventCh())
h.HandleDDLEvent(<-h.DDLEventCh())
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 := h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
@ -91,7 +91,7 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
for i := 0; i < rowCount1; i++ {
testKit.MustExec("insert into t1 values(1, 2)")
}
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1*2))
@ -106,7 +106,7 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
testKit.MustExec("insert into t1 values(1, 2)")
}
testKit.MustExec("commit")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1*3))
@ -122,7 +122,7 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
testKit.MustExec("update t2 set c2 = c1")
}
testKit.MustExec("commit")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1*3))
@ -132,7 +132,7 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
testKit.MustExec("begin")
testKit.MustExec("delete from t1")
testKit.MustExec("commit")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(0))
@ -142,6 +142,33 @@ func (s *testStatsUpdateSuite) TestSingleSessionInsert(c *C) {
rs = testKit.MustQuery("select tot_col_size from mysql.stats_histograms")
rs.Check(testkit.Rows("0", "0", "10", "10"))
// test dump delta only when `modify count / count` is greater than the ratio.
originValue := statistics.DumpStatsDeltaRatio
statistics.DumpStatsDeltaRatio = 0.5
defer func() {
statistics.DumpStatsDeltaRatio = originValue
}()
statistics.DumpStatsDeltaRatio = 0.5
for i := 0; i < rowCount1; i++ {
testKit.MustExec("insert into t1 values (1,2)")
}
h.DumpStatsDeltaToKV(statistics.DumpDelta)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
// not dumped
testKit.MustExec("insert into t1 values (1,2)")
h.DumpStatsDeltaToKV(statistics.DumpDelta)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
h.FlushStats()
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1+1))
}
func (s *testStatsUpdateSuite) TestRollback(c *C) {
@ -159,7 +186,7 @@ func (s *testStatsUpdateSuite) TestRollback(c *C) {
tableInfo := tbl.Meta()
h := s.do.StatsHandle()
h.HandleDDLEvent(<-h.DDLEventCh())
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats := h.GetTableStats(tableInfo)
@ -194,7 +221,7 @@ func (s *testStatsUpdateSuite) TestMultiSession(c *C) {
h.HandleDDLEvent(<-h.DDLEventCh())
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 := h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
@ -214,7 +241,7 @@ func (s *testStatsUpdateSuite) TestMultiSession(c *C) {
testKit.Se.Close()
testKit2.Se.Close()
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1*2))
@ -243,14 +270,14 @@ func (s *testStatsUpdateSuite) TestTxnWithFailure(c *C) {
for i := 0; i < rowCount1; i++ {
testKit.MustExec("insert into t1 values(?, 2)", i)
}
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 := h.GetTableStats(tableInfo1)
// have not commit
c.Assert(stats1.Count, Equals, int64(0))
testKit.MustExec("commit")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
@ -258,13 +285,13 @@ func (s *testStatsUpdateSuite) TestTxnWithFailure(c *C) {
_, err = testKit.Exec("insert into t1 values(0, 2)")
c.Assert(err, NotNil)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1))
testKit.MustExec("insert into t1 values(-1, 2)")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
stats1 = h.GetTableStats(tableInfo1)
c.Assert(stats1.Count, Equals, int64(rowCount1+1))
@ -297,7 +324,7 @@ func (s *testStatsUpdateSuite) TestAutoUpdate(c *C) {
_, err = testKit.Exec("insert into t values ('ss')")
c.Assert(err, IsNil)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Update(is)
err = h.HandleAutoAnalyze(is)
c.Assert(err, IsNil)
@ -313,7 +340,7 @@ func (s *testStatsUpdateSuite) TestAutoUpdate(c *C) {
_, err = testKit.Exec("insert into t values ('fff')")
c.Assert(err, IsNil)
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
c.Assert(h.Update(is), IsNil)
err = h.HandleAutoAnalyze(is)
c.Assert(err, IsNil)
@ -324,7 +351,7 @@ func (s *testStatsUpdateSuite) TestAutoUpdate(c *C) {
_, err = testKit.Exec("insert into t values ('fff')")
c.Assert(err, IsNil)
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
c.Assert(h.Update(is), IsNil)
err = h.HandleAutoAnalyze(is)
c.Assert(err, IsNil)
@ -335,7 +362,7 @@ func (s *testStatsUpdateSuite) TestAutoUpdate(c *C) {
_, err = testKit.Exec("insert into t values ('eee')")
c.Assert(err, IsNil)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
h.Clear()
// We set `Lease` here so that `Update` will use load by need strategy.
h.Lease = time.Second
@ -482,7 +509,7 @@ func (s *testStatsUpdateSuite) TestQueryFeedback(c *C) {
table, err := is.TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
for i, t := range tests {
testKit.MustQuery(t.sql)
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
c.Assert(h.DumpStatsFeedbackToKV(), IsNil)
c.Assert(h.HandleUpdateStats(s.do.InfoSchema()), IsNil)
c.Assert(err, IsNil)
@ -498,7 +525,7 @@ func (s *testStatsUpdateSuite) TestQueryFeedback(c *C) {
// Feedback from limit executor may not be accurate.
testKit.MustQuery("select * from t where t.a <= 2 limit 1")
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
feedback := h.GetQueryFeedback()
c.Assert(len(feedback), Equals, 0)
@ -506,7 +533,7 @@ func (s *testStatsUpdateSuite) TestQueryFeedback(c *C) {
statistics.MaxNumberOfRanges = 0
for _, t := range tests {
testKit.MustQuery(t.sql)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
feedback := h.GetQueryFeedback()
c.Assert(len(feedback), Equals, 0)
}
@ -516,7 +543,7 @@ func (s *testStatsUpdateSuite) TestQueryFeedback(c *C) {
statistics.MaxNumberOfRanges = oriNumber
for _, t := range tests {
testKit.MustQuery(t.sql)
h.DumpStatsDeltaToKV()
h.DumpStatsDeltaToKV(statistics.DumpAll)
feedback := h.GetQueryFeedback()
c.Assert(len(feedback), Equals, 0)
}
@ -554,16 +581,16 @@ func (s *testStatsUpdateSuite) TestOutOfOrderUpdate(c *C) {
// Simulate the case that another tidb has inserted some value, but delta info has not been dumped to kv yet.
testKit.MustExec("insert into t values (2,2),(4,5)")
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
testKit.MustExec(fmt.Sprintf("update mysql.stats_meta set count = 1 where table_id = %d", tableInfo.ID))
testKit.MustExec("delete from t")
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
testKit.MustQuery("select count from mysql.stats_meta").Check(testkit.Rows("1"))
// Now another tidb has updated the delta info.
testKit.MustExec(fmt.Sprintf("update mysql.stats_meta set count = 3 where table_id = %d", tableInfo.ID))
c.Assert(h.DumpStatsDeltaToKV(), IsNil)
c.Assert(h.DumpStatsDeltaToKV(statistics.DumpAll), IsNil)
testKit.MustQuery("select count from mysql.stats_meta").Check(testkit.Rows("0"))
}