MySQL - 错误 1071 阻止更改字符集/排序规则,“指定的键太长......”

Posted

技术标签:

【中文标题】MySQL - 错误 1071 阻止更改字符集/排序规则,“指定的键太长......”【英文标题】:MySQL - change charset/collation prevented by error 1071, "specified key was too long..." 【发布时间】:2018-08-12 05:39:00 【问题描述】:

我正在尝试将我的一个数据库表从 utf8_general_ci 切换到 utf8mb4。

ALTER TABLE d4b80le1jha CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin

这会引发以下错误:

1071 - 指定的密钥太长;最大密钥长度为 1000 字节

我已阅读有关此错误消息的许多答案,但似乎无法解决我的问题。他们中的大多数都在谈论定义新索引,而不是如何处理现有索引。

我也尝试过以recommended here 运行以下命令,但没有任何区别:

SET @@global.innodb_large_prefix = 1;

一个加重因素可能是我使用 varchar 哈希作为主键。这是我无法控制的遗留功能。我没有在我的索引上设置明确的大小 - 我想知道这是否是我应该看的。

表:

Field           Type            Null    Key     Default
-------------------------------------------------------
id              varchar(11)     NO      PRI     NULL    
link            varchar(255)    NO              NULL    
title           varchar(255)    NO              NULL    
description     varchar(255)    YES             NULL    
pubdate         datetime        NO              NULL    
img_url         varchar(255)    YES             NULL    
team_id         varchar(11)     NO      MUL     NULL    
source_id       varchar(11)     NO              NULL    
hits            int(11)         YES             NULL
hits            int(11)         YES             NULL

索引:

Keyname         Type    Unique  Packed  Column      Cardinality Collation   Null
--------------------------------------------------------------------------------
PRIMARY         BTREE   Yes         No  id          13407       A           No
Unique combo    BTREE   Yes         No  team_id                 A           No
                                        source_id               A           No
                                        link        13407       A           No

【问题讨论】:

我自己也遇到了这个错误信息。对我来说,将数据库引擎从 MyISAM 切换到 InnoDB 允许更大的索引大小以适应 utf8mb4 字符集。减少列和索引的大小对我来说是行不通的,我不想在列级别使用字符集。由于 MyISAM 引擎将来会从 mysql 中移除,所以无论如何切换到 InnoDB 是必要的。 【参考方案1】:

这可能是您的Unique combo 索引造成了麻烦,我的意思是您在(team_id, source_id, link) 上的索引。该索引的 字符 总长度为 277,因此其总最大字节长度是 1108 的四倍。

你能做些什么呢?

link 列的字符长度减少到 228,因此索引的最大字符长度为 250。只要您的值仍然合适,这可能是最简单的。

重新创建提及link(228) 而不是仅提及link 的索引以仅索引link 的前导字符。我不知道这是否是个好主意;索引的目的是定义唯一约束。如果你不索引link 的整个值,你就没有这样做。

不要将表中的所有字符列转换为 utfmb4 字符编码,只需转换 titledescription 列。这可能对你有用。为什么?您的 _id 哈希可能使用有限的字符集,根本不需要 unicode。您的 link 列值可能是 URL,也可以使用有限的 (latin1) 字符集。所以,titledescription 可能需要用希伯来语或中文书写,或者包含表情符号或其他内容。这可能是您最好的解决方案。

(请注意,字符编码实际上是逐列指定的。为了方便起见,提供了转换整个表的能力。)

所以你可以这样做

ALTER TABLE d4b80le1jha 
     MODIFY title VARCHAR(255) 
                  CHARACTER SET utf8mb4
                  COLLATE utf8mb4_bin;
ALTER TABLE d4b80le1jha 
     MODIFY description VARCHAR(255) 
                        CHARACTER SET utf8mb4
                        COLLATE utf8mb4_bin;

最后,由于这两列是人类可读的文本,您可能希望使用utf8mb4_general_ci 而非utf8mb4_bin 来整理这些列。搜索和排序可能会更好地满足用户的期望。

【讨论】:

【参考方案2】:

有 5 个步骤可以解决 5.5 和 5.6 中存在的问题,但在 5.7 中已默认消失。

如果您因为尝试使用 CHARACTER SET utf8mb4 而达到限制。这是一种方法:

将限制提高到 3072 字节:

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_large_prefix=1;
logout & login (to get the global values);
ALTER TABLE tbl ROW_FORMAT=DYNAMIC;  -- (or COMPRESSED)

http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes中给出了更多

【讨论】:

“执行以下操作之一”在这里很奇怪。您是否知道自己在说什么,或者只是 复制过去 对任何事情都足够好? ;) @changzhao - 哎呀。感谢您指出。是的,这是一个复制粘贴错误。

以上是关于MySQL - 错误 1071 阻止更改字符集/排序规则,“指定的键太长......”的主要内容,如果未能解决你的问题,请参考以下文章

错误:#1071 - 指定的密钥太长;最大密钥长度为 1000 字节 - mysql 5.0.91

洛谷P1071 潜伏者 字符串

mysql 索引过长1071-max key length is 767 byte

mysql 索引过长1071-max key length is 767 byte

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes