mysql校验字段长度依据字节数而非字符数,utf8mb4下中文占4字节,需用length()查真实字节长度;若max(length(column_name))超目标长度,alter table会失败,须先清理或截断超长数据再执行modify。

查字段真实字节长度,别只看字符数
MySQL校验的是字节数,不是字符数。utf8mb4下1个中文占4字节,CHAR_LENGTH()返回3个字符,LENGTH()才返回12字节——而报错依据是后者。
执行这条语句确认瓶颈:SELECT MAX(LENGTH(column_name)) FROM table_name;
- 结果必须 ≤ 你计划设的新长度(比如想扩到
VARCHAR(500),那MAX(LENGTH())就得 ≤ 500) - 如果超了,
ALTER TABLE ... MODIFY会直接失败,不是警告,是中断DDL - 别用
SELECT LENGTH('中文')测试,它不反映表中实际存储编码;用SHOW CREATE TABLE table_name确认字段字符集
改字段前先清脏数据或截断
ALTER操作默认校验全表数据。早年宽松模式写入的超长值,现在严格模式下就是“脏数据”,不处理就卡死。
两种处理路径:
- 清理:先删掉或UPDATE掉超长记录,例如
DELETE FROM table_name WHERE LENGTH(column_name) > 500; - 截断:用
UPDATE table_name SET column_name = SUBSTRING(column_name, 1, 500) WHERE LENGTH(column_name) > 500;——注意SUBSTRING按字符截,要按字节截得用SUBSTRING(column_name, 1, 500)配合CONVERT或应用层处理 - 执行
ALTER TABLE table_name MODIFY COLUMN column_name VARCHAR(500);前,务必确保MAX(LENGTH())≤ 500
索引前缀没同步更新,扩了也白扩
字段本身扩到VARCHAR(1000),但索引还是INDEX(name(50)),INSERT时仍按前50字节做唯一性判断,可能间接触发Data too long或逻辑异常。
查索引定义:SHOW INDEX FROM table_name WHERE Column_name = 'column_name';,看Sub_part是否大于0。
- 是前缀索引:必须重建,例如
DROP INDEX idx_name ON table_name; CREATE INDEX idx_name ON table_name (column_name(1000)); - 注意InnoDB单索引前缀上限3072字节,utf8mb4下最多支持768字符(3072 ÷ 4),设
(1000)会报错 - TEXT类型字段不能建前缀索引(除非显式指定长度),换类型前先确认索引依赖
TEXT类型比硬扩VARCHAR更稳,但有硬约束
当字段语义就是“可能很长的文本”(如日志、JSON、富文本),TEXT或MEDIUMTEXT比反复扩VARCHAR更可靠——它不受严格模式自动截断影响,也不参与单行65535字节限制计算(走溢出页存储)。
-
TEXT最大65535字节,MEDIUMTEXT支持16MB,LONGTEXT支持4GB;选哪个看实际数据量级 -
TEXT不支持默认值,改之前得先删:ALTER TABLE table_name ALTER COLUMN column_name DROP DEFAULT; - ORM缓存旧schema很常见,改完必须清应用缓存或重启,否则JDBC仍按旧长度预分配参数,照样报错
\N、或Windows换行符\r\n多占2字节——这些不会立刻暴露,直到某条记录刚好卡在边界上。











