症状
错误“MySQL ERROR 1071 — 指定的键过长”指向一个明确的失效模式。下面依次给出症状、定位该原因的检查命令、根本原因、修复方案,以及证明修复有效的验证步骤。
可观察到的症状包括:
- ERROR 1071 (42000): 指定的键过长;最大键长为 3072 字节
- 对 VARCHAR 列添加复合唯一索引失败
- latin1 下可用,切换到 utf8mb4 后失败
诊断
先在隔离环境中复现故障,再按顺序执行以下检查,逐步缩小范围。
步骤 1
mysql -e "CREATE TABLE t (a VARCHAR(1000), INDEX(a))"
错误会给出字节上限,其取决于行格式与列的字符集。
步骤 2
mysql -e "SHOW FULL COLUMNS FROM t\G" | grep -i collation
utf8mb4 解释了 4 倍乘数;更小的字符集或前缀索引可降低大小。
常见诱因(按出现频率排序):
- 对整列建立索引的 VARCHAR 过大,超出索引键字节上限
- utf8mb4 每字符最多 4 字节,使键大小翻数倍
- 跨多个长列的复合索引合计超限
根因
InnoDB 将索引键限制为 3072 字节(DYNAMIC 行格式)。对宽 utf8mb4 VARCHAR 做整列索引可能超限,故 CREATE/ALTER 报 1071。
修复
为列建立前缀索引(INDEX(col(191))),在合适处选用更小字符集,为长值使用哈希列,并让复合键保持在字节预算内。
注意:前缀索引无法强制整列唯一,也不支持按完整值排序;使用前须核对语义。
ALTER TABLE users
ADD INDEX idx_email (email(191)); -- prefix within byte budget
-- unique on full value via a generated hash column
ALTER TABLE users
ADD COLUMN email_hash CHAR(64) AS (SHA2(email, 256)) STORED,
ADD UNIQUE KEY uq_email_hash (email_hash);
-- check the resulting index
SHOW INDEX FROM users;
验证
用前缀重建索引并确认成功;运行 EXPLAIN 确认索引被预期查询使用。
修复后补充一条回归测试,复现原始症状,防止问题再次出现。
这类故障通常是环境问题而非纯逻辑错误,因此在缺陷记录中应写明完整命令、环境变量与工作目录。请用最小的脚本复现,待最小用例清楚后再扩大范围。为这类故障准备一份简短的排查清单,能显著减少下次排障时间。