MySQL 8.0.34无法扩大user_id列长度,报1071错误求助
MySQL 8.0.34 调整列长度后无法重建唯一约束问题
环境与表结构
MySQL版本:8.0.34 CE(64位)
现有表结构:
CREATE TABLE `t_report_subscriptions` ( `subscr_id` int NOT NULL AUTO_INCREMENT, `report_header_id` varchar(700) NOT NULL, `user_id` varchar(45) NOT NULL, `update_type` varchar(45) DEFAULT NULL, `created_date` datetime DEFAULT NULL, `modified_date` datetime DEFAULT NULL, `source_system_id` int DEFAULT NULL, PRIMARY KEY (`subscr_id`), UNIQUE KEY `uq_reportSubsriptions` (`report_header_id`,`user_id`,`source_system_id`), KEY `report_id_fk_idx` (`report_header_id`,`source_system_id`), CONSTRAINT `fk_report_id` FOREIGN KEY (`report_header_id`, `source_system_id`) REFERENCES `l_report_header_data` (`REPORT_HEADER_ID`, `SOURCE_SYSTEM_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
操作过程与报错
- 尝试调整
user_id列长度至256:
alter table t_report_subscriptions modify column user_id varchar(256) NOT NULL;
报错:
Error Code: 1071. Specified key was too long; max key length is 3072 bytes
- 删除约束与索引后调整列长度成功,执行的删除语句:
ALTER TABLE t_report_subscriptions drop index `report_id_fk_idx`; ALTER TABLE t_report_subscriptions drop index `uq_reportSubsriptions`; ALTER TABLE t_report_subscriptions DROP FOREIGN KEY fk_report_id;
- 重建外键与索引成功,但重建唯一约束时再次报错:
ALTER TABLE t_report_subscriptions ADD CONSTRAINT `uq_reportSubsriptions` UNIQUE(`report_header_id`,`user_id`,`source_system_id`);
报错:
16:12:43 ALTER TABLE t_report_subscriptions ADD CONSTRAINT `uq_reportSubsriptions` UNIQUE(`report_header_id`,`user_id`,`source_system_id`) Error Code: 1071. Specified key was too long; max key length is 3072 bytes 0.000 sec
问题原因
InnoDB引擎的索引最大长度限制为3072字节,而表使用utf8mb4字符集(每个字符占4字节):
report_header_idvarchar(700):700×4=2800字节user_idvarchar(256):256×4=1024字节source_system_idint:4字节
三者总长度为2800+1024+4=3828字节,远超3072字节限制,导致唯一约束创建失败。
解决方案
方案1:使用前缀索引缩短列的索引长度
对report_header_id取合适长度的前缀创建唯一约束,确保总长度不超过3072字节。例如取前500个字符:
ALTER TABLE t_report_subscriptions ADD CONSTRAINT `uq_reportSubsriptions` UNIQUE(`report_header_id`(500), `user_id`, `source_system_id`);
注意:需确认前缀长度足够区分不同的
report_header_id值,避免因前缀重复导致业务逻辑冲突。
方案2:修改表字符集为utf8(需评估业务影响)
若业务不需要支持emoji等4字节字符,可将表字符集改为utf8(每个字符占3字节),此时总长度为700×3 + 256×3 +4=2872字节,符合3072字节限制:
ALTER TABLE t_report_subscriptions CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; -- 之后再重建唯一约束 ALTER TABLE t_report_subscriptions ADD CONSTRAINT `uq_reportSubsriptions` UNIQUE(`report_header_id`,`user_id`,`source_system_id`);
方案3:调整唯一键组成或使用哈希索引
- 若业务允许,可简化唯一键的列组合,减少总长度;
- 或计算
report_header_id的哈希值(如MD5)存储为单独列,对哈希列+user_id+source_system_id创建唯一约束,需注意处理哈希冲突场景:
-- 添加哈希列 ALTER TABLE t_report_subscriptions ADD COLUMN `report_header_hash` varchar(32) GENERATED ALWAYS AS (MD5(`report_header_id`)) STORED; -- 创建唯一约束 ALTER TABLE t_report_subscriptions ADD CONSTRAINT `uq_reportSubsriptions` UNIQUE(`report_header_hash`, `user_id`, `source_system_id`);
内容的提问来源于stack exchange,提问作者Avinash Reddy
相关产品推荐
相关产品推荐

