Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

session, statistics: fix "data too long for column 'xxx_bound'" when analyze tables with very long strings (#28800) #29072

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
96 changes: 93 additions & 3 deletions session/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ const (
stats_ver BIGINT(64) NOT NULL DEFAULT 0,
flag BIGINT(64) NOT NULL DEFAULT 0,
correlation DOUBLE NOT NULL DEFAULT 0,
last_analyze_pos BLOB DEFAULT NULL,
last_analyze_pos LONGBLOB DEFAULT NULL,
UNIQUE INDEX tbl(table_id, is_index, hist_id)
);`

Expand All @@ -207,8 +207,8 @@ const (
bucket_id BIGINT(64) NOT NULL,
count BIGINT(64) NOT NULL,
repeats BIGINT(64) NOT NULL,
upper_bound BLOB NOT NULL,
lower_bound BLOB ,
upper_bound LONGBLOB NOT NULL,
lower_bound LONGBLOB ,
ndv BIGINT NOT NULL DEFAULT 0,
UNIQUE INDEX tbl(table_id, is_index, hist_id, bucket_id)
);`
Expand Down Expand Up @@ -495,11 +495,32 @@ const (
// version71 forces tidb_multi_statement_mode=OFF when tidb_multi_statement_mode=WARN
// This affects upgrades from v4.0 where the default was WARN.
version71 = 71
<<<<<<< HEAD
=======
// version72 adds snapshot column for mysql.stats_meta
version72 = 72
// version73 adds mysql.capture_plan_baselines_blacklist table
version73 = 73
// version74 changes global variable `tidb_stmt_summary_max_stmt_count` value from 200 to 3000.
version74 = 74
// version75 update mysql.*.host from char(60) to char(255)
version75 = 75
// version76 update mysql.columns_priv from SET('Select','Insert','Update') to SET('Select','Insert','Update','References')
version76 = 76
// version77 adds mysql.column_stats_usage table
version77 = 77
// version78 updates mysql.stats_buckets.lower_bound, mysql.stats_buckets.upper_bound and mysql.stats_histograms.last_analyze_pos from BLOB to LONGBLOB.
version78 = 78
>>>>>>> de9b5cbb0... session, statistics: fix "data too long for column 'xxx_bound'" when analyze tables with very long strings (#28800)
)

// currentBootstrapVersion is defined as a variable, so we can modify its value for testing.
// please make sure this is the largest version
<<<<<<< HEAD
var currentBootstrapVersion int64 = version71
=======
var currentBootstrapVersion int64 = version78
>>>>>>> de9b5cbb0... session, statistics: fix "data too long for column 'xxx_bound'" when analyze tables with very long strings (#28800)

var (
bootstrapVersion = []func(Session, int64){
Expand Down Expand Up @@ -574,6 +595,16 @@ var (
upgradeToVer69,
upgradeToVer70,
upgradeToVer71,
<<<<<<< HEAD
=======
upgradeToVer72,
upgradeToVer73,
upgradeToVer74,
upgradeToVer75,
upgradeToVer76,
upgradeToVer77,
upgradeToVer78,
>>>>>>> de9b5cbb0... session, statistics: fix "data too long for column 'xxx_bound'" when analyze tables with very long strings (#28800)
}
)

Expand Down Expand Up @@ -1518,6 +1549,65 @@ func upgradeToVer71(s Session, ver int64) {
mustExecute(s, "UPDATE mysql.global_variables SET VARIABLE_VALUE='OFF' WHERE VARIABLE_NAME = 'tidb_multi_statement_mode' AND VARIABLE_VALUE = 'WARN'")
}

<<<<<<< HEAD
=======
func upgradeToVer72(s Session, ver int64) {
if ver >= version72 {
return
}
doReentrantDDL(s, "ALTER TABLE mysql.stats_meta ADD COLUMN snapshot BIGINT(64) UNSIGNED NOT NULL DEFAULT 0", infoschema.ErrColumnExists)
}

func upgradeToVer73(s Session, ver int64) {
if ver >= version73 {
return
}
doReentrantDDL(s, CreateCapturePlanBaselinesBlacklist)
}

func upgradeToVer74(s Session, ver int64) {
if ver >= version74 {
return
}
// The old default value of `tidb_stmt_summary_max_stmt_count` is 200, we want to enlarge this to the new default value when TiDB upgrade.
mustExecute(s, fmt.Sprintf("UPDATE mysql.global_variables SET VARIABLE_VALUE='%[1]v' WHERE VARIABLE_NAME = 'tidb_stmt_summary_max_stmt_count' AND CAST(VARIABLE_VALUE AS SIGNED) = 200", config.GetGlobalConfig().StmtSummary.MaxStmtCount))
}

func upgradeToVer75(s Session, ver int64) {
if ver >= version75 {
return
}
doReentrantDDL(s, "ALTER TABLE mysql.user MODIFY COLUMN Host CHAR(255)")
doReentrantDDL(s, "ALTER TABLE mysql.global_priv MODIFY COLUMN Host CHAR(255)")
doReentrantDDL(s, "ALTER TABLE mysql.db MODIFY COLUMN Host CHAR(255)")
doReentrantDDL(s, "ALTER TABLE mysql.tables_priv MODIFY COLUMN Host CHAR(255)")
doReentrantDDL(s, "ALTER TABLE mysql.columns_priv MODIFY COLUMN Host CHAR(255)")
}

func upgradeToVer76(s Session, ver int64) {
if ver >= version76 {
return
}
doReentrantDDL(s, "ALTER TABLE mysql.columns_priv MODIFY COLUMN Column_priv SET('Select','Insert','Update','References')")
}

func upgradeToVer77(s Session, ver int64) {
if ver >= version77 {
return
}
doReentrantDDL(s, CreateColumnStatsUsageTable)
}

func upgradeToVer78(s Session, ver int64) {
if ver >= version78 {
return
}
doReentrantDDL(s, "ALTER TABLE mysql.stats_buckets MODIFY upper_bound LONGBLOB NOT NULL")
doReentrantDDL(s, "ALTER TABLE mysql.stats_buckets MODIFY lower_bound LONGBLOB")
doReentrantDDL(s, "ALTER TABLE mysql.stats_histograms MODIFY last_analyze_pos LONGBLOB DEFAULT NULL")
}

>>>>>>> de9b5cbb0... session, statistics: fix "data too long for column 'xxx_bound'" when analyze tables with very long strings (#28800)
func writeOOMAction(s Session) {
comment := "oom-action is `log` by default in v3.0.x, `cancel` by default in v4.0.11+"
mustExecute(s, `INSERT HIGH_PRIORITY INTO %n.%n VALUES (%?, %?, %?) ON DUPLICATE KEY UPDATE VARIABLE_VALUE= %?`,
Expand Down
14 changes: 14 additions & 0 deletions statistics/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,17 @@ func (s *testSerialIntegrationSuite) TestOutdatedStatsCheck(c *C) {
c.Assert(h.Update(is), IsNil)
c.Assert(tk.HasPseudoStats("select * from t where a = 1"), IsTrue)
}

func TestAnalyzeLongString(t *testing.T) {
t.Parallel()
store, clean := testkit.CreateMockStore(t)
defer clean()
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t")
tk.MustExec("set @@session.tidb_analyze_version = 2;")
tk.MustExec("create table t(a longtext);")
tk.MustExec("insert into t value(repeat(\"a\",65536));")
tk.MustExec("insert into t value(repeat(\"b\",65536));")
tk.MustExec("analyze table t with 0 topn")
}