症状
本篇调试指南针对“MySQL ERROR 1406 — 数据超出列长度”。内容涵盖可观察的症状、可复现的诊断路径、根本原因、具体修复方式,以及如何验证修复并防止回归。
可观察到的症状包括:
- ERROR 1406 (22001): 第 1 行数据对列 title 过长
- 短字符串插入成功,长字符串失败
- 值视觉上够短,却因 UTF-8 被拒绝
诊断
先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。
步骤 1
mysql -e "SHOW CREATE TABLE posts\G" | grep -i title
声明的长度给出被突破的确切上限。
步骤 2
mysql -e "SELECT CHAR_LENGTH('...'), LENGTH('...')"
CHAR_LENGTH 计字符、LENGTH 计字节,可揭示 UTF-8 的开销。
常见诱因(按出现频率排序):
- 字符串超过列的 VARCHAR 字符长度
- 多字节字符集使字节数超出索引或列限制
- 严格 SQL 模式拒绝截断而非告警
根因
严格模式下,MySQL 拒绝长于列定义的值而非截断。VARCHAR 长度以字符计,但存储与索引预算以字节计,因此多字节内容仍可能超限。
修复
放宽列(VARCHAR/TEXT),插入前校验输入长度,并在为带索引的列定长时考虑字符集字节数。
注意:非严格模式下的静默截断会在无错误的情况下丢数据;应保持严格模式并在应用边界处理长度。
ALTER TABLE posts MODIFY title VARCHAR(500) NOT NULL;
-- validate before insert
INSERT INTO posts (title) SELECT ? WHERE CHAR_LENGTH(?) <= 500;
-- prefer TEXT for arbitrary length
-- ALTER TABLE posts MODIFY title TEXT;
验证
插入此前失败的值并确认成功;验证存储值与输入相等(未截断)。
修复后补充一条回归测试,复现原始症状,防止问题再次出现。
这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。