statistics: async column stats loading mixes UniqueID and column-info ID
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
### 1. Minimal reproduce step (Required)
The following test reproduces the problem:
Path: `pkg/statistics/handle/storage/read_test.go`
```go
func TestRealSQLAsyncLoadQueuesNonMetadataColumnID(t *testing.T) {
clearAsyncLoadHistogramNeededItems()
t.Cleanup(clearAsyncLoadHistogramNeededItems)
store, dom := testkit.CreateMockStoreAndDomain(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set @@session.tidb_analyze_version=2")
tk.MustExec("set @@session.tidb_stats_load_sync_wait = 0")
h := dom.StatsHandle()
oriLease := h.Lease()
h.SetLease(1)
defer func() {
h.SetLease(oriLease)
}()
tk.MustExec("drop table if exists t_mismatch")
tk.MustExec("create table t_mismatch(a int)")
tk.MustExec("alter table t_mismatch add column tmp int")
tk.MustExec("alter table t_mismatch drop column tmp")
tk.MustExec("alter table t_mismatch add column b int")
tk.MustExec("insert into t_mismatch values (1, 2), (2, 3)")
tk.MustExec("analyze table t_mismatch")
is := dom.InfoSchema()
require.NoError(t, h.InitStats(context.Background(), is))
tbl, err := is.TableByName(context.Background(), ast.NewCIStr("test"), ast.NewCIStr("t_mismatch"))
require.NoError(t, err)
tblInfo := tbl.Meta()
colAID := tblInfo.Columns[0].ID
colBID := tblInfo.Columns[1].ID
require.Greater(t, colBID, int64(len(tblInfo.Columns)))
h.Clear()
require.NoError(t, h.InitStats(context.Background(), is))
statsTbl := h.GetPhysicalTableStats(tblInfo.ID, tblInfo)
colB := statsTbl.GetCol(colBID)
require.True(t, colB == nil || colB.IsAllEvicted())
// Real SQL should queue the real metadata column ID for b, but it also queues an extra
// non-metadata ID when planner UniqueID and metadata ID diverge.
tk.MustQuery("select * from t_mismatch where b = 2").Check(testkit.Rows("1 2"))
queuedColIDs := make(map[int64]struct{})
var queuedWrongID int64
require.Eventually(t, func() bool {
clear(queuedColIDs)
queuedWrongID = 0
for _, item := range asyncload.AsyncLoadHistogramNeededItems.AllItems() {
if item.TableID == tblInfo.ID && !item.IsIndex {
queuedColIDs[item.ID] = struct{}{}
if item.ID != colBID {
queuedWrongID = item.ID
}
}
}
_, hasCorrectID := queuedColIDs[colBID]
return queuedWrongID != 0 && hasCorrectID
}, 5*time.Second, 100*time.Millisecond)
require.Contains(t, queuedColIDs, colBID)
require.NotContains(t, queuedColIDs, colAID)
require.NotZero(t, queuedWrongID)
require.NotEqual(t, colBID, queuedWrongID)
// The real async-load path reaches the loader with the wrong ID as well; the loader drops it
// and still loads the correct metadata column stats.
require.NoError(t, h.LoadNeededHistograms(dom.InfoSchema()))
statsTbl = h.GetPhysicalTableStats(tblInfo.ID, tblInfo)
colB = statsTbl.GetCol(colBID)
require.NotNil(t, colB)
require.True(t, colB.IsFullLoad())
}
```
### 2. What did you expect to see? (Required)
Async column stats loading should only enqueue metadata column IDs (`model.ColumnInfo.ID`).
### 3. What did you see instead (Required)
The same query queues:
- the correct metadata column ID for `b`
- an extra wrong non-metadata ID
`LoadNeededHistograms()` later reaches the real loader with that wrong ID and drops it because it cannot be resolved through table metadata. In local repro, the log shows:
```text
Column information not found, possibly due to column being dropped
```
### 4. What is your TiDB version? (Required)
Current local source tree / HEAD: `6c278cb41c`
Contributor guide
Assessment
This issue has not been assessed yet.