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

一、背景

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

vbnet 复制代码
Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

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

二、错误分析

1、错误部分的sql文件

less 复制代码
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个字节。

也就是说:

ini 复制代码
(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、修改字符长度

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

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

2、升级mysql

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

后面再查询中发现一个国外的帖子:

链接:
stackoverflow.com/questions/1...

原文:

vbnet 复制代码
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、查看数据库的存储引擎

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

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

sql 复制代码
show variables like '%character_set%';

3、查看数据库的版本号

lua 复制代码
//进入数据库之后,执行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

相关推荐
妙码生花3 天前
从 PHP 到 AI + Golang,程序员自救转型手记(八):设计管理员模型、热重载配置
前端·后端·go
tyung4 天前
Go 手写 Wait-Free MPSC 无界队列:SwapPointer 实现多生产者无锁入队
后端·go
陈明勇4 天前
Go 1.26 新特性回顾:语言增强、工具升级与 Green Tea GC 默认启用
后端·go
妙码生花5 天前
从 PHP 到 AI + Golang,程序员自救转型手记(二):目录结构、初始化 GIT、设计并开发配置系统
前端·后端·go
leeyi5 天前
Deer-Go:字节 Deer-Flow 的 Go 移植,深度研究 Agent 全拆解
go·aigc·agent
Bolt6 天前
TypeScript 7.0 来了:当 tsc 用 Go 重写之后
javascript·typescript·go
Go_error6 天前
Datatypes:Go 轻松支持数据库JSON类型
后端·go
任沫7 天前
Agent之Function Call
javascript·人工智能·go
唐青枫7 天前
别再把 interface 当万能盒子:Go 接口从隐式实现到项目解耦
go
tyung10 天前
Go 手写有界 SPSC 环形队列:无 CAS、无锁、Cache 友好的无锁模型
后端·go