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


562

当我执行以下命令时:

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

5
因为它不是520个字节,而是2080个字节,远远超过767个字节,所以可以执行column1 varchar(20)和column2 varchar(170)。如果您想使用字符/字节等值,请使用latin1
Rahly

3
我认为您的计算在这里有些错误。mysql使用1或2个额外的字节来记录值的长度:如果列的最大长度为255个字节或更小,则为1个字节;如果长度超过255个字节,则为2个字节。utf8_general_ci编码每个字符需要3个字节,因此varchar(20)使用61个字节,varchar(500)使用1502个字节,共1563个字节
missingovic10

3
mysql>从information_schema.character_sets中选择maxlen,character_set_name其中,character_set_name in('latin1','utf8','utf8mb4'); maxlen | 字符集名称------ | ------------------- 1 | latin1 ------ | ------------------- 3 | utf8 ------ | ------------------- 4 | utf8mb4
missingovic10 '16

15
“如果您想要一个字符/字节等值,请使用latin1”。请勿这样做。Latin1真的很烂。你会后悔的。
Stijn de Witt

有关解决方案,请参考stackoverflow.com/a/52778785/2137210
Pratik,

Answers:


490

在MySQL版本5.6(及更早版本)中,InnoDB表的前缀限制为767个字节。MyISAM表的长度为1,000字节。在MySQL 5.7及更高版本中,此限制已增加到3072字节。

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

您必须采取的一种选择是将下限放在VARCHAR字段上。

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

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

进行调整,您需要获取要应用的密钥,但是我想知道是否值得对有关该实体的数据模型进行检查,以查看是否存在可以使您实现预期业务规则而又不违反MySQL限制的改进。


4
通过指定列的子集而不是整个数量来应用。一个好的解决方案。
史蒂芬

204
这并不能解释为什么远低于长度限制的字段超出了长度限制……
Cerin

6
我已经尝试编辑上面缺少的@Cerin信息,也清楚地认为其他人也缺少它,但由于它更适合用作注释而被拒绝。对于那些试图理解为什么500 + 20> 767的人,请参阅Stefan Endrullis对Julien答案的评论。
Letharion

8
这可能是个问题。例如:我具有字段名称(255),并在使用utf8mb4时在名称(191)处添加唯一字段。如果我让我的用户使用'IJUE3ump5fiUuCi16jSofYS234MLschW4wsIktKiBrTPOTKBK6Vteh5pNuz1tKjy ... aO500mlJs添加他们的名字,而另一个用户使用此'IJUE3ump5fiUuCi16iSyYKK4Br1WTP1KT1KT4KT1KT4K1Br。它应该通过验证,而不会停留在重复输入中。
2013年

28
索引限制为767 个字节,而不是字符。而且由于Mysql的utf8mb4字符集(世界其他地方称为utf8)每个字符最多需要4个字节,因此您最多只能索引VARCHAR(191)。Mysql的utf8字符集(世界其他地方称其为损坏的字符集)每个字符最多需要3个字节,因此,如果您正在使用该字符集(不应使用),则最多可以为VARCHAR(255)
Stijn de Witt

403

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


246
允许的字符数仅取决于您的字符集。每个字符UTF8最多使用3个字节,utf8mb4最多使用4个字节,而latin1仅使用1个字节。因此,对于utf8,您的密钥长度限制为255个字符3*255 = 765 < 767
Stefan Endrullis 2014年

9
这使我免于沮丧-谢谢。考虑到用户使用InnoDB并声称已达到767b限制,这应该是IMO可接受的答案。
TheCarver

8
正如Stefan Endrullis所说,这取决于字符集。如果您使用的UTF8使用3个字节:255x3 = 765(低于767的限制),而256x3 = 768(更高)。但是,如果您使用UTF8mb4的255 * 4 = 1020,那么它不是真正的解决方案
bernhardh

25
这个答案是正确的。但是,如果255确实适合您,则意味着您使用的是Mysql utf8,很不幸,它已损坏。它只能在基本的多语言平面中编码字符。您将遇到字符超出该范围的问题。例如,我认为他们添加的那些表情符号字符不在其范围内。因此VARCHAR(255),与其切换到,而是切换到VARCHAR(191) 并将编码切换到utf8mb4(实际上只是utf8,但MySql希望保持兼容)。
Stijn de Witt

1
对我的多列唯一约束没有帮助。它也不适用于OP的多列唯一约束。(它的总大小为825字节)
Barett

351

当您达到极限时。设置以下内容。

  • 创新数据库 utf8 VARCHAR(255)
  • 创新数据库 utf8mb4 VARCHAR(191)

34
这是最好的答案。简单,直截了当,还包括utf8mb4限制(对于较新的数据库,这是最常用的编码,因为它接受emojis / etc等)。
克劳迪奥·奥兰达

10
因为767/4〜= 191和767/
3〜

11
在哪里以及如何设置?
Dinesh Sunny

1
是的,ENGINE=InnoDB DEFAULT CHARSET=utf8CREATE TABLE语句末尾指定我可以拥有一个VARCHAR(255)主键。谢谢。
xonya

1
有人给他+1以超过限制191 :)
cagcak

147

MySQL假定字符串中每个字符的字节数是最坏的情况。对于MySQL'utf8'编码,每个字符3个字节,因为该编码不允许超出的字符U+FFFF。对于MySQL的“ utf8mb4”编码,每个字符为4个字节,因为这就是MySQL所谓的实际UTF-8。

因此,假设您使用的是“ utf8”,则第一列将占用索引的60个字节,第二列将占用1500个字节。


4
—大概意味着这意味着在使用utf8mb4时,我需要将它们最多设置为191,因为191 * 4 = 764 <767。–
Isaac

2
@Isaac是的,完全是,
morganwahl

2
我认为这可能是正确的答案,但是您能否详细说明解决此问题所需采取的措施?至少对于像我这样的MySQL新手来说?
亚当·格兰特

没有任何方法可以绕过该索引限制。这里的问题是关于独特的约束。对于这些,您可以有一列无限制长度的文本,另一列可以存储该文本的哈希(如MD5),并将哈希列用于唯一约束。您必须确保程序在更改文本时保持哈希值是最新的,但是有多种方法可以解决此问题而不会带来太多麻烦。坦率地说,MySQL应该自己实现这样的事情,因此您不必这样做。如果MariaDB具有内置功能,我不会感到惊讶。
morganwahl

非常长的varchar列上的唯一索引很少。考虑一下为什么需要它,因为这可能是设计问题。如果您只想在其上搜索索引,请考虑一些191个字符以内的“关键字”字段,或将文本分为简短说明和长/完整文本等。或者,如果您确实需要全文搜索,请考虑使用专门的软件它,例如Apache Lucene。
Stijn de Witt

56

在查询之前运行此查询:

SET @@global.innodb_large_prefix = 1;

这将限制增加到3072 bytes


4
全局更改为innodb_large_prefix是否有不利之处?那个数据库是“全局”数据库还是全部“全局”数据库?
SciPhi 2014年

5
仅在使用非标准行格式时适用。参见dev.mysql.com/doc/refman/5.5/en/…。特别是,“对于使用DYNAMIC和COMPRESSED行格式的InnoDB表,启用此选项以允许索引键前缀长于767字节(最多3072字节)。” 默认行格式不受影响。
克里斯里尔

5
这对我来说效果很好-可以在此处找到更多详细信息和指南:Mechanics.flite.com/blog/2014/07/29/…–
cwd

1
之后我们需要重启mysql服务器吗?
SimpleGuy

7
此答案缺少重要的细节。innodb_file_format必须为BARRACUDAand在表级别,您必须使用ROW_FORMAT=DYNAMICROW_FORMAT=COMPRESSED。参见指南上方的@cwd评论。
q0rban '18年

46

Laravel框架解决方案

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

use Illuminate\Support\Facades\Schema;

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

Laravel 5.4。*文档提供的此修复程序的说明

Laravel utf8mb4默认使用字符集,该字符集支持在数据库中存储“表情符号”。如果运行的MySQL版本早于5.7.7发行版或MariaDB版本低于10.2.2,则可能需要手动配置迁移生成的默认字符串长度,以便MySQL为它们创建索引。您可以通过Schema::defaultStringLength在您的AppServiceProvider

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


10
@BojanPetkovic好吧,我只是来自Laravel问题,这个答案实际上解决了我的问题。
mkmnstr

这个答案很好。但是没有人知道,为什么这确实起作用?
UeliDeSchwert

1
@Bobby Laravel文档在标题“ Index Lengths&MySQL / MariaDB”中给出了解释。laravel.com
Ali Shaukat

1
@Bobby我已经更新了答案。我已经添加了laravel文档给出的关于此修复程序的说明。
阿里·肖卡特

39

您正在使用什么字符编码?某些字符集(例如UTF-16等)每个字符使用多个字节。


8
如果是UTF8,则一个字符最多可以使用4个字节,因此20个字符列为20 * 4 + 1字节,而500个字符500 * 4 + 2
列为

5
对于它的价值,我只是遇到了同样的问题,从utf8_general_ci切换到utf8_unicode_ci对我来说解决了这个问题。我不知道为什么,但:(
Andresch Serj

11
对于VARCHAR(256)具有UNIQUE索引的列,更改排序规则对我没有任何效果,就像对@Andresch一样。但是,将长度从256减少到255确实可以解决。我不明白为什么,因为767 /每个字符最多4个字节最多会产生191个?
Arjan 2012年

10
255*3 = 765; 256*3 = 768。看来您的服务器假设每个字符有3个字节,@ Arjan
琥珀色

21
@Greg:您是正确的,但是应该详细说明:UTF-8本身每个代码点使用1-4个字节。MySQL的“字符集”(真正的编码)具有一个称为“ utf8”的字符集,该字符集能够对一些 UTF-8 进行编码,并且每个代码点使用1-3个字节,并且无法对BMP之外的代码点进行编码。它还包括另一个称为“ utf8mb4”的字符集,该字符集每个代码点使用1-4个字节,并且能够对所有Unicode代码点进行编码。(utf8mb4是UTF-8,utf8是UTF-8的怪异版本。)
Thanatos,

28

我认为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个字符。


如果您需要使用比限制更长的列,有两种解决方案:

  1. 使用“便宜”编码(每个字符需要较少字节的编码)
    就我而言,我需要在包含文章SEO字符串的列上添加唯一索引,因为我仅对[A-z0-9\-]SEO 使用字符,所以我使用的latin1_general_ci每个字符仅使用一个字节因此列的长度可以为767个字节。
  2. 从您的列创建哈希并仅在该列上使用唯一索引
    对我来说另一个选择是创建另一个存储SEO哈希的列,此列将具有UNIQUE确保SEO值唯一的键。我还将KEY索引添加到原始SEO列中以加快查找速度。

这成功了。我有varchar(256),我不得不将其更改为varchar(250)。
MaRmAR

25

许多用户已经回答了有关为什么收到错误消息的答案。我的答案是关于如何按原样修复和使用它。

从此链接进行参考。

  1. 打开MySQL客户端(或MariaDB客户端)。它是一个命令行工具。
  2. 它将询问您的密码,输入正确的密码。
  3. 使用此命令选择数据库 use my_database_name;

数据库已更改

  1. set global innodb_large_prefix=on;

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

  1. set global innodb_file_format=Barracuda;

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

  1. 在phpMyAdmin或类似的数据库上转到您的数据库,以便于管理。>选择数据库>查看表结构 >转到操作选项卡。>将ROW_FORMAT更改为DYNAMIC并保存更改。
  2. 转到表格的结构标签>单击唯一按钮。
  3. 做完了 现在它应该没有错误了。

此修复程序的问题是,如果您将db导出到另一台服务器(例如,从localhost到真实主机),并且无法在该服务器上使用MySQL命令行。您不能在那里使它工作。


如果在输入上述查询后仍然出错,请尝试转到“ phpmyadmin”>将“排序规则”设置为您的首选项(对我来说,我使用“ utf8_general_ci”)>单击“应用”(即使它已经是utf8)
安东尼·卡尔

我不使用一个工具,您的指示工作,但我还是投它试图帮助人们用实际修复这个问题。对于导致问题的原因有无尽的解释,但是对于如何真正解决它却很少。
Teekin

20
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个字节。


16

您可以在长列的md5中添加一列


请注意,这将不允许您对这些列进行范围扫描。VARCHAR的前缀长度将使您能够保留此特征,同时在索引中造成可能的虚假匹配(并进行扫描和行查找以消除它们)(请参见接受的答案)。(这实际上是一个手动实现的哈希索引,可悲的是MysQL不支持InnoDB表。)
Thanatos

我不能使用前缀索引,因为出于测试目的,我需要保持与H2的兼容性,并且发现使用哈希列效果很好。我强烈建议使用诸如SHA1的抗冲突功能,而不是MD5,以防止恶意用户创建冲突。如果您的查询之一仅检查哈希值,而不检查完整的列值,则可能利用索引冲突来泄漏数据。
小麦克

16

在您的导入文件中替换utf8mb4utf8

在此处输入图片说明


为什么要这样做呢?此外,如果有任何不利之处(我认为),您应该提及此点
Nico Haase

13

尝试使用utf8mb4将唯一索引添加到VARCHAR(255)字段时,我们遇到了此问题。尽管这里已经很好地概述了问题,但我想就如何解决并解决问题添加一些实用建议。

使用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个长度的字段。


11

这是我的原始答案:

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

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

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

在具有字符集utf8(或 utf8mb4)的VARCHAR列上使用索引,而具有超过一定长度的字符的VARCHAR列实际上是一个问题。如果是utf8mb4,该特定长度为191。

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


解决了openmeetings设置的问题(顺便说一句,您救了我一晚:-)
Ludo

11

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


10

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

varchar(200) 

替换为

varchar(191)

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


这对我也起作用。我有一个varchar(250),但是数据从来没有那么长。将其更改为varchar(100)。谢谢你的主意:)
阿伦·巴兹·拉勒

7

我对此主题进行了一些搜索,终于有了一些自定义更改

对于MySQL Workbench 6.3.7版本,可以使用图形界面阶段

  1. 启动Workbench并选择连接。
  2. 转到管理或实例,然后选择选项文件。
  3. 如果Workbench要求您允许读取配置文件,然后按两次OK,以允许它。
  4. 管理员选项文件窗口位于中心位置。
  5. 转到InnoDB选项卡,如果在“常规”部分中未选中innodb_large_prefix,请检查它。
  6. 将innodb_default_row_format选项值设置为DYNAMIC。

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

  1. 以管理员身份启动CMD。
  2. 转到安装了mysql服务器的目录,大多数情况下,它位于“ C:\ Program Files \ MySQL \ MySQL Server 5.7 \ bin”,因此命令为“ cd \”“ cd Program Files \ MySQL \ MySQL Server 5.7 \ bin”。
  3. 现在运行命令mysql -u userName -p databasecheema现在它要求输入相应用户的密码。提供密码并进入mysql提示符。
  4. 我们必须设置一些全局设置,逐一输入以下命令。innodb_large_prefix = on; 设置全局innodb_file_format = barracuda; 设置全局innodb_file_per_table = true;
  5. 现在,最后,我们必须默认更改必需表的ROW_FORMAT的COMPACT,我们必须将其设置为DYNAMIC。
  6. 使用以下命令alter table table_name ROW_FORMAT = DYNAMIC;
  7. 完成

我找不到:6.将innodb_default_row_format选项值设置为DYNAMIC。
Adrian Cid Almaguer

如果我使用set global innodb_default_row_format = DYNAMIC;我看到这条消息:ERROR 1193(HY000):未知的系统变量“innodb_default_row_format”
阿德里安熙ALMAGUER

您如何从工作台到cmd出错?我是从工作台上直接选择的。
Abhishek

我从CMD这样做是因为我在Workbench中看不到该选项
Adrian Cid Almaguer

1
我看到了这个var在v5.7.9中引入的问题,并且我有v5.6.33版本,谢谢
Adrian Cid Almaguer

7

对于laravel 5.76.0

遵循的步骤

  1. App\Providers\AppServiceProvider.php
  2. 将此添加到提供商 use Illuminate\Support\Facades\Schema;顶部的中。
  3. 在Boot函数内部添加此 Schema::defaultStringLength(191);

全部,享受。


也为Laravel 5.8工作。

这是一个不好的解决方案。原因:索引并不意味着是无限长的。当您对某事物应用唯一索引时,您希望索引在大多数情况下都是固定的。这意味着您不应该使类似的东西变得email独一无二,但是您应该对电子邮件进行哈希处理并使其独一无二。与原始字符串数据不同,哈希值是固定宽度的,可以索引并使其唯一而没有问题。而不是理解问题,您正在传播无法扩展的可怕做法。
NB

5

更改您的排序规则。您可以使用支持几乎所有功能的utf8_general_ci


“几乎”是一个很好的暗示,这不是一个长期解决方案
Nico Haase

4

创建表时只需更改utf8mb4为即可utf8解决我的问题。例如:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


4

要解决此问题,这对我来说就像一种魅力。

ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

我确认我的问题也是数据库排序规则。我对此没有任何解释。我使用mysql v5.6.32,数据库排序规则为utf8mb4_unicode_ci。
mahyard

2

根据下面给出的列,这2个可变字符串列正在使用utf8_general_ci归类(utf8暗含字符集)。

在MySQL中,utf8字符集每个字符最多使用3个字节。因此,它将需要分配500 * 3 = 1500字节,这比MySQL允许的767字节大得多。这就是为什么您会收到此1071错误的原因。

换句话说,您需要根据字符集的字节表示形式来计算字符数,因为并非每个字符集都是一个字节表示形式(如您所假定的那样)utf8。MySQL中的IE 在每个字符最多使用3个字节,即767 /3≈255字符和utf8mb4,最多为4个字节,表示767 /4≈191个字符。

众所周知,MySQL

column1 varchar(20) utf8_general_ci
column2  varchar(500) utf8_general_ci

1

我发现此查询对于检测哪些列的索引违反最大长度很有用:

SELECT
  c.TABLE_NAME As TableName,
  c.COLUMN_NAME AS ColumnName,
  c.DATA_TYPE AS DataType,
  c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
  s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
  ON s.table_name = c.TABLE_NAME
 AND s.COLUMN_NAME = c.COLUMN_NAME 
WHERE c.TABLE_SCHEMA = DATABASE()
  AND c.CHARACTER_MAXIMUM_LENGTH > 191 
  AND c.DATA_TYPE IN ('char', 'varchar', 'text')

1

请检查是否sql_mode

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

如果是,请更改为

sql_mode=NO_ENGINE_SUBSTITUTION

要么

重新启动服务器,更改my.cnf文件(输入以下内容)

innodb_large_prefix=on

1

就我而言,当我使用linux重定向输出/输入字符备份数据库时遇到了这个问题。因此,我如下所述更改语法。PS:使用Linux或Mac终端。

备份(不带>重定向)

# mysqldump -u root -p databasename -r bkp.sql

恢复(没有<redirect)

# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql

错误“指定的密钥太长;最大密钥长度为767字节”简单消失了。


1

索引长度和MySQL / MariaDB


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

use Illuminate\Support\Facades\Schema;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Schema::defaultStringLength(191);
}

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

来自博客的参考: https : //www.scratchcode.io/specified-key-too-long-error-in-laravel/

laravel官方文档的参考资料: https ://laravel.com/docs/5.7/migrations


0

如果您要创建类似:

CREATE TABLE IF NOT EXISTS your_table (
  id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(256) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

它应该像

CREATE TABLE IF NOT EXISTS your_table (
      id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
      name varchar(256) COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (id)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;

但是您需要通过代码检查该列的唯一性,或者添加新列作为varchar列的MD5或SHA1


3
然后,您的唯一密钥丢失了。我认为,更好的办法是简单名称的长度减少至191
haudoing

1
为什么要以编程方式检查唯一性(如果它是本机数据库功能)?
帕维尔Tomkiel

0

由于前缀限制,将发生此错误。在5.7之前的MySQL版本中,InnoDB表的前缀限制为767个字节。MyISAM表的长度为1,000字节。在MySQL 5.7及更高版本中,此限制已增加到3072字节。

在给您错误的服务上运行以下命令可以解决您的问题。这必须在MYSQL CLI中运行。

SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL innodb_file_per_table=on;
SET GLOBAL innodb_large_prefix=on;

-1

将抱怨索引字段的CHARSET更改为“ latin1”,
即ALTER TABLE tbl更改myfield myfield varchar(600)CHARACTER SET latin1 DEFAULT NULL;
latin1每个字符用一个字节代替四个字符


5
如果他尝试插入非拉丁字符怎么办?
帕维尔Tomkiel

4
这是最糟糕的事情。绝对不要那样做。
塞巴斯2015年

1
在我的情况下,它位于仅存储十六进制字符的路径名的列上,因此这可能是某人的解决方案。这实际上取决于您要存储的内容...
codewandler

我不得不对此表示反对,因为在2016AD中使用latin1并不是解决方案。关于在2007年我们不得不将数据库从latin1转换为utf8的时间,我仍然有可怕的噩梦。不漂亮。完全没有
投注Lamed

在存储比特币地址和交易ID的两列的唯一索引上,我遇到了相同的问题。这些将始终是ASCII字符,因此我将在这些列上使用latin1。正在投票。
alexg '16

-2

如果您innodb_log_file_size最近更改过,请尝试恢复以前的值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.