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

wwodge7n  于 2021-06-19  发布在  Mysql
关注(0)|答案(18)|浏览(460)

当我执行以下命令时:

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

我收到了这个错误信息:


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

关于第1列和第2列的信息:

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
2sbarzqh

2sbarzqh1#

如果有人对innodb/utf-8有意见 UNIQUE a上的索引 VARCHAR(256) field,切换到 VARCHAR(255) . 似乎255是限制。

zc0qhyus

zc0qhyus2#

对于laravel 5.7至6.0
遵循的步骤
App\Providers\AppServiceProvider.php .
将此添加到提供程序 use Illuminate\Support\Facades\Schema; 在上面。
在引导函数中添加 Schema::defaultStringLength(191); 就这些,享受吧。

50few1ms

50few1ms3#

替换 utf8mb4utf8 在导入文件中。

hk8txs48

hk8txs484#

以下是我最初的答案:
我只是删除数据库,然后像这样重新创建,错误就消失了: 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-character-set-to-utf8mb4

tpgth1q7

tpgth1q75#

在查询之前运行此查询:

SET @@global.innodb_large_prefix = 1;

这将使限制增加到 3072 bytes .

qvk1mo1f

qvk1mo1f6#

我认为varchar(20)只需要21字节,而varchar(500)只需要501字节。所以总字节数是522,小于767。为什么我会收到错误信息?
utf8需要每个字符3个字节来存储字符串,因此在您的情况下,20+500个字符=203+5003=1560个字节,这超过了允许的767个字节。
utf8的限制是767/3=255个字符,对于每个字符使用4个字节的utf8mb4,限制是767/4=191个字符。

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

使用“更便宜”的编码(每个字符需要更少字节的编码)
在我的例子中,我需要在包含文章的seo字符串的列上添加唯一索引,因为我只使用 [A-z0-9\-] 搜索引擎优化字符,我用 latin1_general_ci 它每个字符只使用一个字节,所以列的长度可以是767字节。
从列中创建哈希,并仅对该列使用唯一索引
我的另一个选择是创建另一个列来存储搜索引擎优化的哈希值,这个列将有 UNIQUE 确保seo值唯一的关键。我还要补充一点 KEY 索引到原始seo列以加快查找速度。

yb3bgrhw

yb3bgrhw7#

Specified key was too long; max key length is 767 bytes

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

5sxhfpxr

5sxhfpxr8#

我在这个主题上做了一些搜索,最后得到了一些自定义更改
对于mysql workbench 6.3.7版本,提供图形化的中间阶段
启动workbench并选择连接。
转到“管理”或“示例”,然后选择“选项”“文件”。
如果workbench请求您读取配置文件的权限,然后通过按两次ok来允许它。
在中心位置出现“管理员选项文件”窗口。
转到innodb选项卡并检查innodb\u large\u前缀(如果在常规部分中未选中)。
将innodb\u default\u row\u 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,它要求输入相应用户的密码。提供密码并输入int

vybvopom

vybvopom9#

我们在尝试使用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 在这里:

这很好,因为常规索引只是用来帮助mysql更快地搜索数据。整个字段不需要索引。
那么,为什么mysql会自动截断常规索引的索引,而在尝试对唯一索引执行此操作时却抛出显式错误呢?好吧,为了让mysql能够判断被插入或更新的值是否已经存在,它实际上需要索引整个值,而不仅仅是其中的一部分。
在一天结束时,如果您想在一个字段上有一个唯一的索引,那么该字段的全部内容必须适合该索引。对于utf8mb4,这意味着将varchar字段长度减少到191个字符或更少。如果该表或字段不需要utf8mb4,可以将其放回utf8,并能够保留255个长度字段。

lf5gs5x2

lf5gs5x210#

5种解决方法:
5.7.7(10.2.2?)中提高了限制。并且可以通过5.6(10.1)中的一些工作来增加。
如果因为尝试使用字符集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

dauxcl2d

dauxcl2d11#

我通过以下方法解决了此问题:

varchar(200)

替换为

varchar(191)

所有具有200个以上的唯一或主要varchar键都将它们替换为191或将它们设置为文本。

ctehm74n

ctehm74n12#

mysql假设字符串中每个字符的字节数为最坏情况。对于mysql'utf8'编码,即每个字符3字节,因为该编码不允许超过3个字符 U+FFFF . 对于mysql'utf8mb4'编码,它是每个字符4个字节,因为mysql称之为实际的utf-8。
因此,假设您使用的是“utf8”,第一列将占用索引的60字节,第二列将占用另外1500字节。

xiozqbni

xiozqbni13#

关于为什么会收到错误消息的答案已经被这里的许多用户回答了。我的答案是如何修复和使用它。
请参阅此链接。
打开mysql客户端(或mariadb客户端)。它是一个命令行工具。
它会询问你的密码,输入正确的密码。
使用此命令选择数据库 use my_database_name; 数据库已更改 set global innodb_large_prefix=on; 查询正常,0行受影响(0.00秒) set global innodb_file_format=Barracuda; 查询正常,0行受影响(0.02秒)
访问phpmyadmin或类似的数据库以便于管理。>选择“数据库”>“查看表结构”>“转到操作选项卡”。>将行格式更改为动态并保存更改。
转到表的结构选项卡>单击唯一按钮。
完成。现在它应该没有错误了。
此修复程序的问题是,如果将db导出到另一台服务器(例如从localhost到real host),并且不能在该服务器中使用mysql命令行。你不能在那里工作。

pdtvr36n

pdtvr36n14#

你用什么字符编码?有些字符集(如utf-16等)每个字符使用超过一个字节。

w41d8nur

w41d8nur15#

laravel框架的解决方案
根据laravel 5.4.*文件;必须在 boot 方法 app/Providers/AppServiceProvider.php 文件如下:

use Illuminate\Support\Facades\Schema;

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

laravel 5.4给出了此修复的说明。*文档:
拉威尔使用 utf8mb4 字符集,包括在数据库中存储“emojis”的支持。如果您运行的mysql版本早于5.7.7版本或10.2.2版本,则可能需要手动配置迁移生成的默认字符串长度,以便mysql为其创建索引。您可以通过调用 Schema::defaultStringLength 方法 AppServiceProvider .
或者,您可以启用 innodb_large_prefix 数据库的选项。有关如何正确启用此选项的说明,请参阅数据库文档。

相关问题