当前位置:  开发笔记 > 编程语言 > 正文

#1071 - 指定密钥太长; 最大密钥长度为767字节

如何解决《#1071-指定密钥太长;最大密钥长度为767字节》经验,为你挑选了19个好方法。

当我执行以下命令时:

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

我收到此错误消息:

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

有关column1和column2的信息:

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

OMG Ponies.. 444

767字节是MySQL版本5.6(和先前版本)中InnoDB表的规定前缀限制.MyISAM表的长度为1,000字节.在MySQL 5.7及更高版本中,此限制已增加到3072字节.

您还必须要注意,如果您在一个大字符或varchar字段上设置了一个索引,该字段为utf8mb4编码,则必须将最大索引前缀长度767字节(或3072字节)除以4,结果为191.这是因为utf8mb4字符的最大长度为4个字节.对于utf8字符,它将是三个字节,导致最大索引前缀长度为254.

您可以选择的一个选项是在VARCHAR字段上设置下限.

另一种选择(根据对此问题的回答)是获取列的子集而不是整个量,即:

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

调整需要获取密钥以进行调整,但我想知道是否值得查看有关此实体的数据模型,看看是否有改进可以让您实现预期的业务规则而不会遇到MySQL限制.



1> OMG Ponies..:

767字节是MySQL版本5.6(和先前版本)中InnoDB表的规定前缀限制.MyISAM表的长度为1,000字节.在MySQL 5.7及更高版本中,此限制已增加到3072字节.

您还必须要注意,如果您在一个大字符或varchar字段上设置了一个索引,该字段为utf8mb4编码,则必须将最大索引前缀长度767字节(或3072字节)除以4,结果为191.这是因为utf8mb4字符的最大长度为4个字节.对于utf8字符,它将是三个字节,导致最大索引前缀长度为254.

您可以选择的一个选项是在VARCHAR字段上设置下限.

另一种选择(根据对此问题的回答)是获取列的子集而不是整个量,即:

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

调整需要获取密钥以进行调整,但我想知道是否值得查看有关此实体的数据模型,看看是否有改进可以让您实现预期的业务规则而不会遇到MySQL限制.


这并不能解释为什么远低于长度限制的字段超出了长度限制...
索引限制是767**字节**,而不是字符.而且由于Mysql的`utf8mb4`字符集(世界其他地方称为utf8)需要(最多)[每个字符4个字节](https://stijndewitt.com/2014/08/09/max-bytes-in- a-utf-8-char /)你只能索引到`VARCHAR(191)`.Mysql的`utf8`字符集(世界其他地方称之为中断)每个字符最多需要3个字节,所以如果你正在使用它(你[不应该](https://stijndewitt.com/2015/06/) 15/use-mysql-utf8mb4-if-you-want-full-unicode-support /)),你可以索引到`VARCHAR(255)`
这可能是个问题.例如:我有字段名称(255)并在名称(191)为此字段添加唯一,因为我正在使用utf8mb4.如果我有我的用户有"IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs"与其他用户用这个"IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJa"不同的是最后一个字符添加自己的名字加上自己的名字.它应该通过验证而不会卡在重复条目中.
我已经尝试编辑@Cerin上面缺少的信息,这显然也被其他人遗漏了,但它被拒绝为更适合作为评论.对于那些试图理解为什么500 + 20> 767的人,请参阅Stefan Endrullis对Julien答案的评论.
通过指定列的子集而不是整个数量来应用.一个好的解决方案

2> PinkTurtle..:

如果有人遇到INNODB/Utf-8尝试UNIQUEVARCHAR(256)字段上放置索引的问题,请将其切换为VARCHAR(255).似乎255是限制.


允许的字符数取决于您的字符集.UTF8每个字符最多可使用3个字节,utf8mb4最多可使用4个字节,而latin1最多只能使用1个字节.因此,对于utf8,您的密钥长度限制为255个字符,因为`3*255 = 765 <767`.
这个答案是对的.**但是**如果255确实适合你,那就意味着你正在使用Mysql`utf8`,遗憾的是它已被破坏.它只能编码基本多语言平面中的字符.你会遇到不属于这个问题的角色问题.例如,我认为他们添加的那些表情符号字符不属于它.因此,不要切换到`VARCHAR(255)`,而是切换到`VARCHAR(191)`*并*将编码切换为`utf8mb4`(实际上只是utf8,但MySql想要保留.compat).
这给我带来了很多挫折 - 谢谢.它应该是IMO接受的答案,考虑到用户使用InnoDB声称它们达到了767b的限制.
AS Stefan Endrullis说,这取决于charset.如果你使用UTF8使用3个字节:255x3 = 765低于767限制,而256x3 = 768更高.但是如果你使用UTF8mb4它的255*4 = 1020,那么它不是一个真正的解决方案

3> Aley..:

当你达到极限.设置以下内容.

INNODB utf8 VARCHAR(255)

INNODB utf8mb4 VARCHAR(191)


这是最好的答案.简单,直截了当,还包括`utf8mb4`限制(对于较新的数据库,它是最常用的编码,因为它接受emojis/etc).
因为767/4~ = 191,而767/3~ = 255
在哪里以及如何设置它?

4> morganwahl..:

MySQL假设字符串中每个字符的字节数最差.对于MySQL'utf8'编码,每个字符3个字节,因为该编码不允许超出字符U+FFFF.对于MySQL的'utf8mb4'编码,它是每个字符4个字节,因为这就是MySQL所谓的实际UTF-8.

所以假设你正在使用'utf8',你的第一列将占据索引的60个字节,而你的第二列将占用1500个字节.


- 这可能意味着当使用utf8mb4时,我需要将它们设置为(最多)191为191*4 = 764 <767.
@Isaac是的,确切地说,

5> Raza Ahmed..:

在查询之前运行此查询:

SET @@global.innodb_large_prefix = 1;

这将增加限制3072 bytes.


仅在使用非标准行格式时适用.请参阅http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_large_prefix.具体来说,'对于使用DYNAMIC和COMPRESSED行格式的InnoDB表,启用此选项以允许长度超过767字节(最多3072字节)的索引键前缀.默认行格式不受影响.
这对我来说效果很好 - 更多细节和指南可以在这里找到:http://mechanics.flite.com/blog/2014/07/29/using-innodb-large-prefix-to-avoid-error-1071/
此答案的重要缺失细节.`innodb_file_format`必须是`BARRACUDA`并且在表级你必须使用`ROW_FORMAT = DYNAMIC`或`ROW_FORMAT = COMPRESSED`.请参阅上面的@cwd的评论和指南.
全局更改为innodb_large_prefix有什么缺点吗?那个数据库是"全球"还是所有数据库全部都是全球?

6> 小智..:

Laravel框架的解决方案

根据Laravel 5.4.*文件 ; 您必须bootapp/Providers/AppServiceProvider.php文件方法中设置默认字符串长度,如下所示:

use Illuminate\Support\Facades\Schema;

public function boot() 
{
    Schema::defaultStringLength(191); 
}

由Laravel 5.4.*文档给出的此修复的解释:

Laravel utf8mb4默认使用字符集,其中包括支持在数据库中存储"emojis".如果您运行的是早于5.7.7版本的MySQL版本或早于10.2.2版本的MariaDB,您可能需要手动配置迁移生成的默认字符串长度,以便MySQL为它们创建索引.您可以通过调用Schema::defaultStringLength您的方法来配置它AppServiceProvider.

或者,您可以innodb_large_prefix为数据库启用该选项.有关如何正确启用此选项的说明,请参阅数据库的文档.


@BojanPetkovic我刚刚来自Laravel问题,这个答案实际上解决了我的问题.
这是幸运的答案..如果它不在这里,我会浪费时间..

7> Amber..:

你使用什么字符编码?某些字符集(如UTF-16等)每个字符使用多个字节.


@Greg:你是对的,但是应该详细说明:UTF-8本身每个代码点使用1-4个字节.MySQL的"字符集"(真正的编码)有一个名为"utf8"的字符集,能够编码_some_的UTF-8,每个代码点使用1-3个字节,并且无法编码BMP之外的代码点.它还包括另一个名为"utf8mb4"的字符集,每个代码点使用1-4个字节,并且能够编码所有Unicode代码点.(utf8mb4是UTF-8,utf8是UTF-8的奇怪版本.)
对于具有`UNIQUE`索引的`VARCHAR(256)`列,更改排序对我没有任何影响,就像对@Andresch一样.但是,将长度从256减少到255确实解决了这个问题.我不明白为什么,因为每个字符767/max 4个字节最多会产生191个字节?
`255*3 = 765; 256*3 = 768`.看来你的服务器每个字符占用3个字节,@ Arjan
如果它是UTF8,则一个字符最多可以使用4个字节,因此20个字符的列是"20*4 + 1"字节,500个char列是"500*4 + 2"个字节
为了它的价值,我遇到了同样的问题,从utf8_general_ci切换到utf8_unicode_ci解决了我的问题.我不知道为什么虽然:(
@Thanatos:utf8最多使用3. SELECT MAXLEN FROM information_schema.CHARACTER_SETS WHERE CHARACTER_SET_NAME ='utf8';

8> Buksy..:

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

UTF8每个字符需要3个字节来存储字符串,所以在你的情况下20 + 500个字符= 20*3 + 500*3 = 1560个字节,这允许的767个字节多.

UTF8的限制是767/3 = 255个字符,对于UTF8mb4,每个字符使用4个字节,它是767/4 = 191个字符.


如果您需要使用比限制更长的列,则有两种解决方案可以解决此问题:

    使用"更便宜"的编码(每个字符需要更少字节的编码)
    在我的情况下,我需要在包含SEO文章的列上添加唯一索引,因为我只使用[A-z0-9\-]SEO的字符,我使用的latin1_general_ci每个字符只使用一个字节所以列的长度可以是767字节.

    从你的列创建哈希并仅在其上使用唯一索引.
    对我来说,另一个选项是创建另一个存储SEO哈希的列,此列将具有UNIQUE确保SEO值唯一的关键.我还会添加KEY索引到原始的SEO列,以加快查找.



9> vee..:

许多用户已经回答了有关您收到错误消息的原因的答案.我的答案是关于如何修复和使用它.

请参阅此链接.

    打开MySQL客户端(或MariaDB客户端).它是一个命令行工具.

    它会询问您的密码,输入正确的密码.

    使用此命令选择数据库 use my_database_name;

数据库已更改

    set global innodb_large_prefix=on;

查询正常,0行受影响(0.00秒)

    set global innodb_file_format=Barracuda;

查询OK,0行受影响(0.02秒)

    转到phpMyAdmin上的数据库或类似的东西,以便于管理.>选择数据库>查看表结构 >转到" 操作"选项卡.>将ROW_FORMAT更改为DYNAMIC并保存更改.

    转到表格的结构选项卡>单击" 唯一"按钮.

    完成.现在它应该没有错误.

此修复的问题是如果将db导出到另一个服务器(例如从localhost导出到真实主机),并且您无法在该服务器中使用MySQL命令行.你无法在那里工作.



10> Anthony Rutl..:
Specified key was too long; max key length is 767 bytes

您收到该消息是因为只有在使用latin-1字符集时,1个字节才等于1个字符.如果使用utf8,则在定义键列时,每个字符将被视为3个字节.如果使用utf8mb4,则在定义键列时,每个字符将被视为4个字节.因此,您需要将键字段的字符限制乘以1,3或4(在我的示例中)以确定键字段尝试允许的字节数.如果您使用的是uft8mb4,则只能为本机InnoDB主键字段定义191个字符.只是不要破坏767字节.



11> diyism..:

你可以添加一列md5的长列



12> maknz..:

尝试使用utf8mb4向VARCHAR(255)字段添加UNIQUE索引时遇到此问题.虽然这里已经很好地概述了这个问题,但我想为我们如何解决这个问题添加一些实用的建议并解决它.

使用utf8mb4时,字符计为4个字节,而在utf8下,它们可以为3个字节.InnoDB数据库有一个限制,索引只能包含767个字节.所以当使用utf8时,你可以存储255个字符(767/3 = 255),但是使用utf8mb4,你只能存储191个字符(767/4 = 191).

您绝对可以VARCHAR(255)使用utf8mb4 为字段添加常规索引,但会发生的情况是索引大小会自动截断为191个字符 - 如下所示unique_key:

Sequel Pro屏幕截图显示截断为191个字符的索引

这很好,因为常规索引仅用于帮助MySQL更快地搜索数据.整个字段不需要编入索引.

那么,为什么MySQL会自动为常规索引截断索引,但在尝试为唯一索引执行时会抛出显式错误?好吧,为了让MySQL能够确定插入或更新的值是否已经存在,它需要实际索引整个值而不仅仅是其中的一部分.

在一天结束时,如果要在字段上具有唯一索引,则该字段的全部内容必须适合索引.对于utf8mb4,这意味着将VARCHAR字段长度减少到191个字符或更少.如果您不需要utf8mb4用于该表或字段,则可以将其删回到utf8并保留255个长度字段.



13> Châu Hồng Lĩ..:

这是我原来的答案:

我只是丢弃数据库并重新创建这样,错误消失了:

drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;

但是,它并不适用于所有情况.

实际上是在VARCHAR列上使用带有字符集utf8(或 utf8mb4)的索引的问题,其中VARCHAR列具有超过一定长度的字符.在这种情况下utf8mb4,某一长度是191.

有关如何在MySQL数据库中使用长索引的更多信息,请参阅本文中的长索引部分:http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-字符集到utf8mb4



14> flik..:

我用以下方法解决了这个问题:

varchar(200) 

替换为

varchar(191)

所有大于200的varchar都用191替换它们或将其设​​置为文本。



15> Rick James..:

5解决方法:

该限制是在5.7.7(MariaDB 10.2.2?)中提高的。可以通过5.6(10.1)中的一些工作来增加它。

如果由于尝试使用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 values 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.
?  Or... Stay with older version 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)

- http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes



16> Abhishek..:

我做了一些关于这个话题的搜索终于得到了一些自定义的改

对于MySQL工作台6.3.7版本可以使用图形交互阶段

    启动Workbench并选择连接.

    转到管理或实例,然后选择选项文件.

    如果Workbench要求您允许读取配置文件,然后按两次OK以允许它.

    在中心位置管理员选项文件窗口到来.

    如果未在"常规"部分中选中,请转到InnoDB选项卡并检查innodb_large_prefix.

    将innodb_default_row_format选项值设置为DYNAMIC.

对于6.3.7以下的版本,直接选项不可用,因此需要使用命令提示符

    以管理员身份启动CMD.

    转到安装mysql服务器的导演大多数情况下它位于"C:\ Program Files\MySQL\MySQL Server 5.7\bin"所以命令是"cd \""cd Program Files\MySQL\MySQL Server 5.7\bin".

    现在运行命令mysql -u userName -p databasescheema现在它要求各个用户的密码.提供密码并进入mysql提示符.

    我们必须设置一些全局设置,逐个输入以下命令设置全局innodb_large_prefix = on; set global innodb_file_format = barracuda; set global innodb_file_per_table = true;

    现在最后我们必须默认改变所需表的ROW_FORMAT它的COMPACT我们必须将它设置为DYNAMIC.

    使用以下命令alter table table_name ROW_FORMAT = DYNAMIC;

    完成



17> Nids Barthwa..:

改变你的整理.你可以使用几乎支持所有的utf8_general_ci



18> Manojkiran.A..:

对于Laravel 5.7或5.6或5.8

遵循的步骤

    转到App\Providers\AppServiceProvider.php

    将此添加到use Illuminate\Support\Facades\Schema;顶部的提供程序 中。

    在Boot函数内部添加此 Schema::defaultStringLength(191);

全部,享受。



19> Bryan..:

在您的导入文件中替换utf8mb4utf8

推荐阅读
个性2402852463
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有