@@ -16,6 +16,8 @@ package cache
16
16
17
17
import (
18
18
"context"
19
+ "slices"
20
+ "strconv"
19
21
"sync/atomic"
20
22
"time"
21
23
@@ -64,19 +66,35 @@ func NewStatsCacheImplForTest() (types.StatsCache, error) {
64
66
}
65
67
66
68
// Update reads stats meta from store and updates the stats map.
67
- func (s * StatsCacheImpl ) Update (ctx context.Context , is infoschema.InfoSchema ) error {
69
+ func (s * StatsCacheImpl ) Update (ctx context.Context , is infoschema.InfoSchema , tableAndPartitionIDs ... int64 ) error {
68
70
start := time .Now ()
69
71
lastVersion := s .GetNextCheckVersionWithOffset ()
70
72
var (
71
- rows []chunk.Row
72
- err error
73
+ skipMoveForwardStatsCache bool
74
+ rows []chunk.Row
75
+ err error
73
76
)
74
77
if err := util .CallWithSCtx (s .statsHandle .SPool (), func (sctx sessionctx.Context ) error {
75
- rows , _ , err = util .ExecRows (
76
- sctx ,
77
- "SELECT version, table_id, modify_count, count, snapshot from mysql.stats_meta where version > %? order by version" ,
78
- lastVersion ,
79
- )
78
+ query := "SELECT version, table_id, modify_count, count, snapshot from mysql.stats_meta where version > %? "
79
+ args := []any {lastVersion }
80
+
81
+ if len (tableAndPartitionIDs ) > 0 {
82
+ // When updating specific tables, we skip incrementing the max stats version to avoid missing
83
+ // delta updates for other tables. The max version only advances when doing a full update.
84
+ skipMoveForwardStatsCache = true
85
+ // Sort and deduplicate the table IDs to remove duplicates
86
+ slices .Sort (tableAndPartitionIDs )
87
+ tableAndPartitionIDs = slices .Compact (tableAndPartitionIDs )
88
+ // Convert table IDs to strings since the SQL executor only accepts string arrays for IN clauses
89
+ tableStringIDs := make ([]string , 0 , len (tableAndPartitionIDs ))
90
+ for _ , tableID := range tableAndPartitionIDs {
91
+ tableStringIDs = append (tableStringIDs , strconv .FormatInt (tableID , 10 ))
92
+ }
93
+ query += "and table_id in (%?) "
94
+ args = append (args , tableStringIDs )
95
+ }
96
+ query += "order by version"
97
+ rows , _ , err = util .ExecRows (sctx , query , args ... )
80
98
return err
81
99
}); err != nil {
82
100
return errors .Trace (err )
@@ -150,7 +168,13 @@ func (s *StatsCacheImpl) Update(ctx context.Context, is infoschema.InfoSchema) e
150
168
tables = append (tables , tbl )
151
169
}
152
170
153
- s .UpdateStatsCache (tables , deletedTableIDs )
171
+ s .UpdateStatsCache (types.CacheUpdate {
172
+ Updated : tables ,
173
+ Deleted : deletedTableIDs ,
174
+ Options : types.UpdateOptions {
175
+ SkipMoveForward : skipMoveForwardStatsCache ,
176
+ },
177
+ })
154
178
dur := time .Since (start )
155
179
tidbmetrics .StatsDeltaLoadHistogram .Observe (dur .Seconds ())
156
180
return nil
@@ -191,12 +215,12 @@ func (s *StatsCacheImpl) replace(newCache *StatsCache) {
191
215
}
192
216
193
217
// UpdateStatsCache updates the cache with the new cache.
194
- func (s * StatsCacheImpl ) UpdateStatsCache (tables [] * statistics. Table , deletedIDs [] int64 ) {
218
+ func (s * StatsCacheImpl ) UpdateStatsCache (cacheUpdate types. CacheUpdate ) {
195
219
if enableQuota := config .GetGlobalConfig ().Performance .EnableStatsCacheMemQuota ; enableQuota {
196
- s .Load ().Update (tables , deletedIDs )
220
+ s .Load ().Update (cacheUpdate . Updated , cacheUpdate . Deleted , cacheUpdate . Options . SkipMoveForward )
197
221
} else {
198
222
// TODO: remove this branch because we will always enable quota.
199
- newCache := s .Load ().CopyAndUpdate (tables , deletedIDs )
223
+ newCache := s .Load ().CopyAndUpdate (cacheUpdate . Updated , cacheUpdate . Deleted )
200
224
s .replace (newCache )
201
225
}
202
226
}
0 commit comments