如何解决mysql中“指定的键太长,最大键长度为255字节”?

brvekthn  于 2023-04-04  发布在  Mysql
关注(0)|答案(3)|浏览(140)

每当我从一个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 server 5.7,ubuntu 16.04
我在[mysqld]下尝试在我的.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服务。它仍然不工作。
任何帮助我都感激不尽。谢谢。

cu6pst1q

cu6pst1q1#

编辑

问题似乎与TINYTEXT数据类型有关。(我可以使用InnoDB或MyISAM复制MySQL版本5.7.17-0ubuntu0.16.04.1-log的观察行为。)
简短的答案(作为解决方法,如何解决1071警告)是使用数据类型**VARCHAR(255)代替TINYTEXT**。
我用各种字符集运行了几个测试用例(utf8,utf8 mb 4,latin 1)并使用InnoDB和MyISAM存储引擎。1071警告似乎与TINYTEXT列的索引中指定的前缀长度有关...似乎是MySQL对前缀长度的限制(与InnoDB没有特别的关系,因为我可以用MyISAM复制这种行为。)除了TINYTEXT,我没有用任何其他TEXT类型进行测试。

以前的回答

InnoDB表的索引键长度限制为767字节。
键定义中的name(255)指定了name的前255个字符。使用MySQL utf8字符集,一个字符可以占用1到3个字节。255乘以3是765。加上int private_id的4个字节,就是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

zsbz8rwp

zsbz8rwp2#

这里有5个解决方案。
如果你是因为尝试使用CHARACTER SET utf8 mb 4而达到限制。那么请执行以下操作之一(每种操作都有缺点)以避免错误:

⚈  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)) * 非常 * 可能是错误的。它说“x和 * 部分 * y的组合是唯一的”。它没有说x和 * 全部 * 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)
i7uq4tfw

i7uq4tfw3#

这个问题在5.7.7提高限值之前就存在

相关问题