MySQL错误#1071 - 指定的键太长;最大键长度为767字节。

667

当我执行了以下命令:

ALTER TABLE `mytable` ADD UNIQUE (
`column1` ,
`column2`
);

我看到了这个错误信息:

#1071 - Specified key was too long; max key length is 767 bytes

列1和列2的信息:

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

我认为varchar(20)只需要21个字节,而varchar(500)只需要501个字节。所以总共的字节数是522,少于767。那么为什么我会收到错误信息呢?

#1071 - Specified key was too long; max key length is 767 bytes

5
因为它不是520字节,而是2080字节,远远超过了767字节,所以你可以将列1设置为varchar(20),将列2设置为varchar(170)。如果您想要字符/字节等效,请使用latin1编码。 - Rahly
3
我认为你的计算有点错误。MySQL会使用额外的1或2个字节来记录值的长度:如果该列的最大长度小于或等于255字节,则使用1个字节,否则使用2个字节。utf8_general_ci编码每个字符需要3个字节,因此varchar(20)使用61个字节,varchar(500)总共使用1502个字节,加起来一共是1563个字节。 - lackovic10
3
mysql> 从information_schema.character_sets中选择maxlen和character_set_name,其中character_set_name为('latin1', 'utf8', 'utf8mb4')。
maxlen character_set_name
1 latin1
------ -------------------
3 utf8
------ -------------------
4 utf8mb4
- lackovic10
26
如果你需要一个字符/字节的等价物,可以使用Latin1。但是请不要这样做。使用Latin1会带来很多问题,你会后悔的。 - Stijn de Witt
请参考以下链接获取有关该问题的解决方案:https://dev59.com/s1gQ5IYBdhLWcg3w6IEH#52778785 - Pratik
37个回答

1

我已经将varchar更改为nvarchar,对我有用。


1

好的,根据我的情况,我需要将一个MySQL 5.7的数据库文件恢复到MySQL 5.6,并且我遇到了这个问题。

根本原因是版本不兼容,一些被索引的列长度超过了191(默认为255)

因此解决方案很简单:将所有“已索引列”的长度设置为小于191的数字(例如180)

在这里输入图片描述


0
如果你正在创建类似于以下内容的东西:
CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

它应该是类似于这样的东西

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

但是您需要从代码中检查该列的唯一性,或者添加一个新列作为varchar列的MD5或SHA1。


3
您的唯一密钥丢失了。我认为更好的方法是将名称长度简单地缩短到191。 - haudoing
1
为什么要在程序中检查唯一性,如果这是本地数据库的功能呢? - Paweł Tomkiel

-1

对我来说,关于“#1071 - 指定的键太长;最大键长度为767字节”的问题,在将主键/唯一键组合更改为限制列大小为200后得到了解决。

ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);

你能解释一下那个数字200是从哪里来的吗?如果其他答案包含一个较低的数字,比如191,那么为什么要用这个数字? - Nico Haase

-2

如果您最近更改了innodb_log_file_size,请尝试恢复之前有效的值。


-2

我对这个问题的修复是添加一个选项作为第三个参数:字符集

queryInterface.createTable(
  tableName,
  { /*... columns*/ },
  { charset: 'utf8' } 
)

否则Sequelize会创建UTF8MB4表。

使用 utf8mb4 会有任何问题吗? - Nico Haase

-4

将出问题的索引字段的字符集更改为"latin1"
即 ALTER TABLE tbl CHANGE myfield myfield varchar(600) CHARACTER SET latin1 DEFAULT NULL;
latin1 每个字符只占用一个字节,而不是四个字节


7
如果他尝试插入非Latin1字符,该怎么办? - Paweł Tomkiel
4
这是最糟糕的事情,不要做。永远不要这样做。 - Sebas
1
在我的情况下,它位于一个仅存储十六进制字符路径名的列上...所以这可能是某人的解决方案。这实际上取决于您想要存储什么... - codewandler
我不得不给这个点踩,因为在2016年使用latin1并不是一个解决方案。我仍然对我们不得不在2007年将数据库从latin1转换为utf8的时间感到恐惧。呃,一点也不美丽。 - Bet Lamed
我在一个包含比特币地址和交易ID的两列唯一索引上遇到了同样的问题。这些字符始终是ASCII字符,因此我将在这些列上使用latin1。点赞。 - alexg
根据列中将要存储的内容,我认为这个解决方案没有问题。我的数据库已从latin1迁移到utf8,也经历了那场噩梦,但考虑到该列仅存储URL或文件路径等内容,如果MySQL 5.7不是一个选项,我会考虑使用它。点赞。 - Uriel Bertoche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接