如何解析 "specified key was too long max key length is 255 bytes" in mysql?

How to resolve "specified key was too long max key length is 255 bytes" in mysql?

每当我从 mysql 客户端 (emma) 之一触发此查询时:

CREATE TABLE `tbl_mappings` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `private_id` int(11) unsigned NOT NULL,
  `name` tinytext NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`private_id`,`name`(255)),
  KEY `FK_tbl__private_integrations_mappings_tbl__private_integrations` (`private_id`),
  CONSTRAINT `FK_tbl__private_integrations_mappings_tbl__private_integrations` FOREIGN KEY (`private_id`) REFERENCES `tbl__private_integrations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我收到错误消息:指定的密钥太长,最大密钥长度为 255 字节

我正在使用 mysql 服务器 5.7,ubuntu 16.04

而且我尝试在 [mysqld] 下的 my.cnf 中添加配置:

innodb_file_format=barracuda
innodb_file_per_table=1
innodb_large_prefix=1
init_connect='SET collation_connection = utf8mb4_unicode_ci'
init_connect='SET NAMES utf8mb4'
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-storage-engine=InnoDB

然后重新启动 mysql 服务。仍然无法正常工作。

感谢任何帮助。 谢谢。

编辑

问题似乎与 TINYTEXT 数据类型有关。 (我可以使用 InnoDB 或 MyISAM 使用 MySQL 版本 5.7.17-0ubuntu0.16.04.1-log 复制观察到的行为。)

简短的回答(作为解决方法,如何解决 1071 警告)是使用数据类型 VARCHAR(255) 代替 TINYTEXT.


我 运行 几个具有各种字符集(utf8、utf8mb4、latin1)并使用 InnoDB 和 MyISAM 存储引擎的测试用例。 1071 警告似乎与 TINYTEXT 列的索引中指定的前缀长度有关...似乎是前缀长度的 MySQL 限制(与 InnoDB 没有特别相关,因为我可以复制行为MyISAM。)除了 TINYTEXT 之外,我没有使用任何其他 TEXT 类型进行测试。


上一个答案

InnoDB 表的索引键长度限制为 767 字节。

键定义中的 name(255) 指定 name 的前 255 个字符。使用 MySQL utf8 字符集,一个字符可以占用一到三个字节。 255乘以3是765,加上int的四个字节private_id,就是769,超出了最大值

这就是您收到错误的原因。

解决该问题的几种方法。

最简单的方法是减少索引中名称的字符数,例如

UNIQUE KEY `name` (`private_id`,`name`(254))

如果这不能满足您的用例,那么您可能需要考虑使用已弃用的 innodb_large_prefix 设置。您需要使用 DYNAMICCOMPRESSED 行格式。请参阅此处的讨论:

https://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format-specification.html

有 5 个解 here .

如果您因为尝试使用 CHARACTER SET utf8mb4 而达到限制。然后执行以下操作之一(每个都有缺点)以避免错误:

⚈  Upgrade to 5.7.7 for 3072 byte limit -- your cloud may not provide this; 
⚈  Change 255 to 191 on the VARCHAR -- you lose any keys longer than 191 characters (unlikely?); 
⚈  ALTER .. CONVERT TO utf8 -- you lose Emoji and some of Chinese; 
⚈  Use a "prefix" index -- you lose some of the performance benefits. 
⚈  Stay with 5.6/5.5/10.1 but perform 4 steps to raise the limit to 3072 bytes: 

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)

一看,别用TINYTEXT,改成VARCHAR(255),不需要前缀!

乍一看,UNIQUE(x, y(255))非常可能是错误的。它说 "the combination of x and part of y is unique"。它没有说 x 所有 of y 是唯一的。

第四...5.7是哪个版本?适用于 5.7.15:

mysql> CREATE TABLE `tbl_mappings` (
    ->   `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    ->   `private_id` int(11) unsigned NOT NULL,
    ->   `name` tinytext NOT NULL,
    ->   PRIMARY KEY (`id`),
    ->   UNIQUE KEY `name` (`private_id`,`name`(255)),
    ->   KEY `private_id` (`private_id`)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    -> ;
Query OK, 0 rows affected (0.03 sec)

mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.7.15    |
+-----------+
1 row in set (0.00 sec)

mysql> SHOW CREATE TABLE tbl_mappings\G
*************************** 1. row ***************************
       Table: tbl_mappings
Create Table: CREATE TABLE `tbl_mappings` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `private_id` int(11) unsigned NOT NULL,
  `name` tinytext NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`private_id`,`name`(255)),
  KEY `private_id` (`private_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)