Skip to content

Commit 3dac0cd

Browse files
0xPoeti-chi-bot
authored andcommitted
This is an automated cherry-pick of pingcap#56287
Signed-off-by: ti-chi-bot <[email protected]>
1 parent 781794d commit 3dac0cd

File tree

10 files changed

+2136
-0
lines changed

10 files changed

+2136
-0
lines changed

executor/infoschema_reader.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ func (e *memtableRetriever) setDataFromTables(ctx context.Context, sctx sessionc
683683

684684
createOptions := ""
685685

686+
<<<<<<< HEAD:executor/infoschema_reader.go
686687
if checker != nil && !checker.RequestVerification(sctx.GetSessionVars().ActiveRoles, schema.Name.L, table.Name.L, "", mysql.AllPrivMask) {
687688
continue
688689
}
@@ -697,6 +698,52 @@ func (e *memtableRetriever) setDataFromTables(ctx context.Context, sctx sessionc
697698
hasAutoIncID, _ := infoschema.HasAutoIncrementColumn(table)
698699
if hasAutoIncID {
699700
autoIncID, err = getAutoIncrementID(sctx, schema, table)
701+
=======
702+
if checker != nil && !checker.RequestVerification(sctx.GetSessionVars().ActiveRoles, schema.L, table.Name.L, "", mysql.AllPrivMask) {
703+
return rows, nil
704+
}
705+
pkType := "NONCLUSTERED"
706+
if !table.IsView() {
707+
if table.GetPartitionInfo() != nil {
708+
createOptions = "partitioned"
709+
} else if table.TableCacheStatusType == model.TableCacheStatusEnable {
710+
createOptions = "cached=on"
711+
}
712+
var autoIncID any
713+
hasAutoIncID, _ := infoschema.HasAutoIncrementColumn(table)
714+
if hasAutoIncID {
715+
autoIncID = getAutoIncrementID(e.is, sctx, table)
716+
}
717+
tableType := "BASE TABLE"
718+
if util.IsSystemView(schema.L) {
719+
tableType = "SYSTEM VIEW"
720+
}
721+
if table.IsSequence() {
722+
tableType = "SEQUENCE"
723+
}
724+
if table.HasClusteredIndex() {
725+
pkType = "CLUSTERED"
726+
}
727+
shardingInfo := infoschema.GetShardingInfo(schema, table)
728+
var policyName any
729+
if table.PlacementPolicyRef != nil {
730+
policyName = table.PlacementPolicyRef.Name.O
731+
}
732+
733+
var rowCount, avgRowLength, dataLength, indexLength uint64
734+
if useStatsCache {
735+
// Even for partitioned tables, we must update the stats cache for the main table itself.
736+
// This is necessary because the global index length from the table also needs to be included.
737+
// For further details, see: https://github.com/pingcap/tidb/issues/54173
738+
err := cache.TableRowStatsCache.UpdateByID(sctx, table.ID)
739+
if err != nil {
740+
return rows, err
741+
}
742+
if table.GetPartitionInfo() != nil {
743+
// needs to update all partitions for partition table.
744+
for _, pi := range table.GetPartitionInfo().Definitions {
745+
err := cache.TableRowStatsCache.UpdateByID(sctx, pi.ID)
746+
>>>>>>> 2214bd07fc6 (statistics: Remove the ineffective dirty IDs from the row count cache (#56287)):pkg/executor/infoschema_reader.go
700747
if err != nil {
701748
return err
702749
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
// Copyright 2023 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a Copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// TableRowStatsCache is the cache of table row count.
16+
17+
package cache
18+
19+
import (
20+
"strconv"
21+
"strings"
22+
"time"
23+
24+
"github.com/pingcap/tidb/pkg/meta/model"
25+
"github.com/pingcap/tidb/pkg/sessionctx"
26+
"github.com/pingcap/tidb/pkg/statistics/handle/util"
27+
"github.com/pingcap/tidb/pkg/types"
28+
"github.com/pingcap/tidb/pkg/util/chunk"
29+
"github.com/pingcap/tidb/pkg/util/syncutil"
30+
)
31+
32+
// TableRowStatsCache is the cache of table row count.
33+
var TableRowStatsCache = &StatsTableRowCache{
34+
tableRows: make(map[int64]uint64),
35+
colLength: make(map[tableHistID]uint64),
36+
}
37+
38+
// tableStatsCacheExpiry is the expiry time for table stats cache.
39+
var tableStatsCacheExpiry = 3 * time.Second
40+
41+
type tableHistID struct {
42+
tableID int64
43+
histID int64
44+
}
45+
46+
// StatsTableRowCache is used to cache the count of table rows.
47+
type StatsTableRowCache struct {
48+
tableRows map[int64]uint64
49+
colLength map[tableHistID]uint64
50+
mu syncutil.RWMutex
51+
}
52+
53+
// GetTableRows gets the count of table rows.
54+
func (c *StatsTableRowCache) GetTableRows(id int64) uint64 {
55+
c.mu.RLock()
56+
defer c.mu.RUnlock()
57+
return c.tableRows[id]
58+
}
59+
60+
// GetColLength gets the length of the column.
61+
func (c *StatsTableRowCache) GetColLength(id tableHistID) uint64 {
62+
c.mu.RLock()
63+
defer c.mu.RUnlock()
64+
return c.colLength[id]
65+
}
66+
67+
// UpdateByID tries to update the cache by table ID.
68+
func (c *StatsTableRowCache) UpdateByID(sctx sessionctx.Context, id int64) error {
69+
tableRows, err := getRowCountTables(sctx, id)
70+
if err != nil {
71+
return err
72+
}
73+
colLength, err := getColLengthTables(sctx, id)
74+
if err != nil {
75+
return err
76+
}
77+
c.mu.Lock()
78+
defer c.mu.Unlock()
79+
c.tableRows[id] = tableRows[id]
80+
for k, v := range colLength {
81+
c.colLength[k] = v
82+
}
83+
return nil
84+
}
85+
86+
// EstimateDataLength returns the estimated data length in bytes of a given table info.
87+
// Returns row count, average row length, total data length, and all indexed column length.
88+
func (c *StatsTableRowCache) EstimateDataLength(table *model.TableInfo) (
89+
rowCount uint64, avgRowLength uint64, dataLength uint64, indexLength uint64) {
90+
rowCount = c.GetTableRows(table.ID)
91+
dataLength, indexLength = c.GetDataAndIndexLength(table, table.ID, rowCount)
92+
if table.GetPartitionInfo() != nil {
93+
// For partition table, data only stores in partition level.
94+
// Keep `indexLength` for global index.
95+
rowCount, dataLength = 0, 0
96+
for _, pi := range table.GetPartitionInfo().Definitions {
97+
piRowCnt := c.GetTableRows(pi.ID)
98+
rowCount += piRowCnt
99+
parDataLen, parIndexLen := c.GetDataAndIndexLength(table, pi.ID, piRowCnt)
100+
dataLength += parDataLen
101+
indexLength += parIndexLen
102+
}
103+
}
104+
avgRowLength = uint64(0)
105+
if rowCount != 0 {
106+
avgRowLength = dataLength / rowCount
107+
}
108+
109+
if table.IsSequence() {
110+
// sequence is always 1 row regardless of stats.
111+
rowCount = 1
112+
}
113+
return
114+
}
115+
116+
func getRowCountTables(sctx sessionctx.Context, tableIDs ...int64) (map[int64]uint64, error) {
117+
var rows []chunk.Row
118+
var err error
119+
if len(tableIDs) == 0 {
120+
rows, _, err = util.ExecWithOpts(sctx, nil, "select table_id, count from mysql.stats_meta")
121+
} else {
122+
inTblIDs := buildInTableIDsString(tableIDs)
123+
sql := "select table_id, count from mysql.stats_meta where " + inTblIDs
124+
rows, _, err = util.ExecWithOpts(sctx, nil, sql)
125+
}
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
rowCountMap := make(map[int64]uint64, len(rows))
131+
for _, row := range rows {
132+
tableID := row.GetInt64(0)
133+
rowCnt := row.GetUint64(1)
134+
rowCountMap[tableID] = rowCnt
135+
}
136+
return rowCountMap, nil
137+
}
138+
139+
func buildInTableIDsString(tableIDs []int64) string {
140+
var whereBuilder strings.Builder
141+
whereBuilder.WriteString("table_id in (")
142+
for i, id := range tableIDs {
143+
whereBuilder.WriteString(strconv.FormatInt(id, 10))
144+
if i != len(tableIDs)-1 {
145+
whereBuilder.WriteString(",")
146+
}
147+
}
148+
whereBuilder.WriteString(")")
149+
return whereBuilder.String()
150+
}
151+
152+
func getColLengthTables(sctx sessionctx.Context, tableIDs ...int64) (map[tableHistID]uint64, error) {
153+
var rows []chunk.Row
154+
var err error
155+
if len(tableIDs) == 0 {
156+
sql := "select table_id, hist_id, tot_col_size from mysql.stats_histograms where is_index = 0"
157+
rows, _, err = util.ExecWithOpts(sctx, nil, sql)
158+
} else {
159+
inTblIDs := buildInTableIDsString(tableIDs)
160+
sql := "select table_id, hist_id, tot_col_size from mysql.stats_histograms where is_index = 0 and " + inTblIDs
161+
rows, _, err = util.ExecWithOpts(sctx, nil, sql)
162+
}
163+
if err != nil {
164+
return nil, err
165+
}
166+
167+
colLengthMap := make(map[tableHistID]uint64, len(rows))
168+
for _, row := range rows {
169+
tableID := row.GetInt64(0)
170+
histID := row.GetInt64(1)
171+
totalSize := row.GetInt64(2)
172+
if totalSize < 0 {
173+
totalSize = 0
174+
}
175+
colLengthMap[tableHistID{tableID: tableID, histID: histID}] = uint64(totalSize)
176+
}
177+
return colLengthMap, nil
178+
}
179+
180+
// GetDataAndIndexLength gets the data and index length of the table.
181+
func (c *StatsTableRowCache) GetDataAndIndexLength(info *model.TableInfo, physicalID int64, rowCount uint64) (dataLength, indexLength uint64) {
182+
columnLength := make([]uint64, len(info.Columns))
183+
for i, col := range info.Columns {
184+
if col.State != model.StatePublic {
185+
continue
186+
}
187+
var length uint64
188+
if storageLen := col.FieldType.StorageLength(); storageLen != types.VarStorageLen {
189+
length = rowCount * uint64(storageLen)
190+
} else {
191+
length = c.GetColLength(tableHistID{tableID: physicalID, histID: col.ID})
192+
}
193+
dataLength += length
194+
columnLength[i] = length
195+
}
196+
197+
for _, idx := range info.Indices {
198+
if idx.State != model.StatePublic {
199+
continue
200+
}
201+
if info.GetPartitionInfo() != nil {
202+
// Global indexes calculated in table level.
203+
if idx.Global && info.ID != physicalID {
204+
continue
205+
}
206+
// Normal indexes calculated in partition level.
207+
if !idx.Global && info.ID == physicalID {
208+
continue
209+
}
210+
}
211+
for _, col := range idx.Columns {
212+
if col.Length == types.UnspecifiedLength {
213+
indexLength += columnLength[col.Offset]
214+
} else {
215+
indexLength += rowCount * uint64(col.Length)
216+
}
217+
}
218+
}
219+
return dataLength, indexLength
220+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "history",
5+
srcs = ["history_stats.go"],
6+
importpath = "github.com/pingcap/tidb/pkg/statistics/handle/history",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//pkg/meta/model",
10+
"//pkg/sessionctx",
11+
"//pkg/statistics/handle/logutil",
12+
"//pkg/statistics/handle/storage",
13+
"//pkg/statistics/handle/types",
14+
"//pkg/statistics/handle/util",
15+
"//pkg/statistics/util",
16+
"//pkg/util/intest",
17+
"@com_github_pingcap_errors//:errors",
18+
"@org_uber_go_zap//:zap",
19+
],
20+
)

0 commit comments

Comments
 (0)