导入sql文件报错:1071 Specified key was too long; max key length is 767 bytes

本文介绍了解决MySQL数据库中因主键长度超过限制而引发的错误的方法。通过分析错误原因,给出了调整字符长度及升级MySQL版本两种解决方案,并分享了相关知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景

今天把服务器的数据库导出了一份sql文件,准备导入到本地,但是在导入的时候,报了个错:

Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

这就很奇怪了,明明服务器上都可以,凭什么我这边就报错呢。

二、错误分析

1、错误部分的sql文件

CREATE TABLE `model_has_permissions` (
  `permission_id` int(10) unsigned NOT NULL,
  `model_id` int(10) unsigned NOT NULL,
  `model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`permission_id`,`model_id`,`model_type`),
  KEY `model_has_permissions_model_id_model_type_index` (`model_id`,`model_type`),

就是这个primary key部分报错的。错误信息的意思是,设置的键长超过了767 bytes。

2、这个767 bytes是什么玩意?

答:
(1)
在mysql 5.5.3之前,mysql的InnoDB引擎,要求设置的主键长度不得超过767bytes。
mysql的MyIsam引擎的主键长度不得超过1000 bytes。

(2)
在mysql中,gbk字符集会占用2个字节。utf8字符会占用3个字节。
而且从mysql5.5.3之后的版本,mysql 开始支持utf8m4字符,代表着一个字符占用4个字节。

也就是说:

(255+10+10)*3 = 825  //在用utf8作为字符集的时候,超过了规定的767 bytes
(255+10+10)*2 = 550  //当该用gbk作为字符集的时候
(255+10+10)*4 = 1100  //当用utf8m4作为字符集的时候,也超标了

3、大致原因知道之后,查看sql文件

(1)、数据库使用的InnoDB引擎
(2)、数据库使用utf8m4作为字符集

三、解决办法

1、修改字符长度

//根据上面的分析可以进行计算,我的主键长度不能超过192
768/4 = 192

但这样很明显是不符合的需求的,不能随便改动数据库的字段!

2、升级mysql

这个方案是在查询服务器数据库版本的时候,发现服务器数据库采用的是mysql5.7版本。。也就是说在升级数据库之后,是完全可以达到的。。

后面再查询中发现一个国外的帖子:
链接:
https://stackoverflow.com/questions/1814532/1071-specified-key-was-too-long-max-key-length-is-767-bytes

原文:

767 bytes is the stated prefix limitation for InnoDB tables in MySQL version 5.6 (and prior versions). It's 1,000 bytes long for MyISAM tables. In MySQL version 5.7 and upwards this limit has been increased to 3072 bytes.

原文的意思是说,在mysql的5.5.3版本之前,InnoDB引擎的主键对应的最大字节数是767字节,MyISAM对应的主键最大字节是1000字节。但是在mysql5.7版本之后,最大主键字节增大为3072字节。

OK,这样就很明显了,升级mysql是最佳的选择。用集成环境的小伙伴可以关闭集成环境中的mysql,然后下载最新的mysql版本即可。

四、在解决问题时,学到的东西

1、查看数据库的存储引擎

//进入数据库,执行这个命令
show variables like '%storage_engine%';

2、查看当前数据库的字符编码

show variables like '%character_set%';

3、查看数据库的版本号

//进入数据库之后,执行status即可
mysql>status

4、关于varchar

MySQL5.0.3之前varchar(n)这里的n表示字节数

MySQL5.0.3之后varchar(n)这里的n表示字符数,比如varchar(200),不管是英文还是中文都可以存放200个

5、关于用varchar作为主键,不好的地方

      varchar相对于int来说占用磁盘空间多,磁盘io也会多,然后内存带宽也会多。这点上尤其在innodb更为明显,innodb表的Secondary index的 leaf page中都要保存primary key的值,主键如果是varchar,会导致secondary index的体积会比较大。而且varchar主键在比较上也会慢一些,插入时容易发送数据的非顺序插入,导致碎片,index tree效率比int低

end

<think>好的,我现在要解决用户的问题,他在MySQL 5.5.37版本导入SQL文件时遇到了“Specified key was too long; max key length is 767 bytes”的错误。首先,我需要回忆一下之前学过的关于MySQL索引长度限制的知识。 根据用户提供的引用内容,特别是引用[1]和[2],了解到在MySQL 5.6及之前版本,InnoDB表的索引前缀长度限制是767字节,而MyISAM是1000字节。用户提到的是5.5.37版本,显然属于较早的版本,所以默认情况下,这个限制是存在的,而且没有像5.7之后那样支持更大的索引长度。此外,引用[1]还提到innodb_large_prefix参数在5.6引入,但用户用的是5.5,这个参数可能不存在,所以不能通过开启它来解决。 接下来,用户可能需要调整索引结构。引用[4]中提到可以通过限制字段的前缀长度来避免超过限制。例如,对于varchar(255)使用utf8mb4编码的情况,每个字符占4字节,255*4=1020字节,超过了767。所以需要计算允许的最大长度,比如767/4≈191,所以将前缀长度设置为191。这可能是解决方法之一。 另外,引用[3]提到升级到更高版本如5.7或8.0,因为默认支持更大的索引长度。但用户可能因为环境限制无法升级,所以需要提供不升级的解决方案。 还可能涉及到修改表的存储引擎,比如换成MyISAM,但MyISAM在5.5中的索引限制是1000字节,可能不足以解决某些情况,而且InnoDB更常用,所以可能不是最佳方案。 还有可能检查并修改表的行格式,如引用[5]提到的Barracuda格式,但不确定在5.5是否支持,需要查阅文档。如果支持,可能需要同时启用innodb_file_format和innodb_file_per_table,并结合ROW_FORMAT=DYNAMIC或COMPRESSED来允许更大的索引长度。不过,在5.5版本中,这些参数是否有效需要确认。 所以综合来看,可能的解决方案包括: 1. 调整索引列的前缀长度,使其不超过191个字符(对于utf8mb4)。 2. 修改表结构,将varchar字段的长度减少到符合限制。 3. 更改字符集为占用更少字节的编码,如utf8(每个字符3字节),这样最大长度可以是767/3≈255。 4. 如果允许,升级MySQL到5.7或更高版本,默认支持更大的索引。 5. 修改存储引擎为MyISAM,但需注意事务支持等问题。 6. 调整行格式和相关参数,但可能在5.5中不可行。 需要验证这些方法的适用性。例如,在5.5中是否支持ROW_FORMAT=DYNAMIC,以及修改字符集是否可行。同时,用户可能需要手动修改SQL文件中的索引定义,或者导出时指定参数来缩短索引。 此外,用户可能需要备份数据,修改创建表的语句,然后重新导入。这需要具体的步骤指导,比如如何计算合适的索引长度,如何修改SQL文件中的相关部分。 最后,需要提醒用户这些方法可能的影响,比如缩短索引长度可能影响查询性能,或者修改字符集可能导致数据存储变化。因此,建议在测试环境中先行尝试,并备份原数据。</think>### MySQL 5.5.37索引长度限制解决方案 #### 问题原因分析 在MySQL 5.5.37版本中,InnoDB存储引擎的**单列索引最大长度限制为767字节**。若索引列使用`utf8mb4`字符集(每个字符占4字节),当字段长度超过$767/4 \approx 191$时,直接创建索引会触发该错误[^2]。例如: ```sql varchar(255) CHARACTER SET utf8mb4 -- 255*4=1020字节 >767字节 ``` --- #### 解决方案(无需升级版本) 1. **调整索引前缀长度** - 修改索引定义,限制字段的前缀长度: ```sql ALTER TABLE table_name ADD INDEX index_name (column_name(191)); ``` - 若使用联合索引,需确保所有字段总长度不超过限制: $$总字节数 = \sum (字段长度 \times 字符字节数) \leq 767$$ 2. **修改字符集降低字节占用** - 将字段字符集改为`utf8`(3字节/字符): ```sql ALTER TABLE table_name MODIFY column_name VARCHAR(255) CHARACTER SET utf8; -- 255*3=765字节 <767字节 ``` 3. **缩短字段定义长度** - 直接减少字段长度: ```sql ALTER TABLE table_name MODIFY column_name VARCHAR(191) CHARACTER SET utf8mb4; ``` 4. **强制使用MyISAM引擎(非事务场景)** - MyISAM引擎允许1000字节索引长度[^2]: ```sql CREATE TABLE (...) ENGINE=MyISAM; ``` --- #### 操作步骤(以调整前缀长度为例) 1. **定位错误索引** - 检查SQL文件中触发错误的`CREATE INDEX`或`ALTER TABLE`语句。 2. **手动修改SQL文件** ```sql -- 原错误语句 ALTER TABLE users ADD INDEX email_idx (email); -- 修改后 ALTER TABLE users ADD INDEX email_idx (email(191)); ``` 3. **重新导入SQL文件** ```bash mysql -u root -p database_name < modified_file.sql ``` --- #### 补充说明 - **字符集与字节关系**: | 字符集 | 单字符字节数 | 允许最大字段长度varchar) | |----------|--------------|---------------------------| | utf8mb4 | 4 | 191 | | utf8 | 3 | 255 | | latin1 | 1 | 767 | - **升级版本的优势**: MySQL 5.7+默认开启`innodb_large_prefix`,索引长度上限提升至3072字节[^3]。建议在条件允许时升级至MySQL 8.0,避免此类限制。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁柱同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值