当我执行以下命令时:
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限制.
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限制.
如果有人遇到INNODB/Utf-8尝试UNIQUE
在VARCHAR(256)
字段上放置索引的问题,请将其切换为VARCHAR(255)
.似乎255是限制.
当你达到极限.设置以下内容.
INNODB utf8
VARCHAR(255)
INNODB utf8mb4
VARCHAR(191)
MySQL假设字符串中每个字符的字节数最差.对于MySQL'utf8'编码,每个字符3个字节,因为该编码不允许超出字符U+FFFF
.对于MySQL的'utf8mb4'编码,它是每个字符4个字节,因为这就是MySQL所谓的实际UTF-8.
所以假设你正在使用'utf8',你的第一列将占据索引的60个字节,而你的第二列将占用1500个字节.
在查询之前运行此查询:
SET @@global.innodb_large_prefix = 1;
这将增加限制3072 bytes
.
Laravel框架的解决方案
根据Laravel 5.4.*文件 ; 您必须boot
在app/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
为数据库启用该选项.有关如何正确启用此选项的说明,请参阅数据库的文档.
你使用什么字符编码?某些字符集(如UTF-16等)每个字符使用多个字节.
我认为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列,以加快查找.
许多用户已经回答了有关您收到错误消息的原因的答案.我的答案是关于如何修复和使用它.
请参阅此链接.
打开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命令行.你无法在那里工作.
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字节.
你可以添加一列md5的长列
尝试使用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
:
这很好,因为常规索引仅用于帮助MySQL更快地搜索数据.整个字段不需要编入索引.
那么,为什么MySQL会自动为常规索引截断索引,但在尝试为唯一索引执行时会抛出显式错误?好吧,为了让MySQL能够确定插入或更新的值是否已经存在,它需要实际索引整个值而不仅仅是其中的一部分.
在一天结束时,如果要在字段上具有唯一索引,则该字段的全部内容必须适合索引.对于utf8mb4,这意味着将VARCHAR字段长度减少到191个字符或更少.如果您不需要utf8mb4用于该表或字段,则可以将其删回到utf8并保留255个长度字段.
这是我原来的答案:
我只是丢弃数据库并重新创建这样,错误消失了:
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
我用以下方法解决了这个问题:
varchar(200)
替换为
varchar(191)
所有大于200的varchar都用191替换它们或将其设置为文本。
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
我做了一些关于这个话题的搜索终于得到了一些自定义的改
对于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;
完成
改变你的整理.你可以使用几乎支持所有的utf8_general_ci
对于Laravel 5.7或5.6或5.8
遵循的步骤
转到App\Providers\AppServiceProvider.php
。
将此添加到use Illuminate\Support\Facades\Schema;
顶部的提供程序 中。
在Boot函数内部添加此 Schema::defaultStringLength(191);
全部,享受。
在您的导入文件中替换utf8mb4
为utf8
。