#1071指定的关键是太长;最关键的长度是767字节
-
06-07-2019 - |
题
当我执行以下命令:
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
解决方案
767字节是所声明的前缀限制 MySQL版本5.6(和以前的版本)中的InnoDB表。 MyISAM表的长度为1,000字节。在MySQL 5.7及更高版本中,此限制已增加到3072字节。
您还必须注意,如果在utf8mb4编码的大字符或varchar字段上设置索引,则必须将最大索引前缀长度767字节(或3072字节)除以4,结果为191。这是因为utf8mb4字符的最大长度是四个字节。对于utf8字符,它将是三个字节,导致最大索引前缀长度为254。
您可以选择在VARCHAR字段上设置下限。
另一个选项(根据对此问题的回复)是获取列的子集而不是整个量,即:
ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );
调整,因为你需要获取密钥才能应用,但我想知道是否值得查看有关此实体的数据模型,看看是否有改进可以让你实现预期的业务规则而不需要MySQL限制。
其他提示
如果有任何人遇到INNODB / Utf-8尝试在UNIQUE
字段上放置VARCHAR(256)
索引的问题,请将其切换为VARCHAR(255)
。似乎255是限制。
当你打的限制。设置以下。
- 少
utf8
VARCHAR(255)
- 少
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
的限制。
您使用的字符编码是什么?某些字符集(如UTF-16等)每个字符使用多个字节。
Laravel Framework解决方案
根据 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
选项 数据库。有关的说明,请参阅数据库的文档 如何正确启用此选项。
我认为varchar(20)只需要21个字节,而varchar(500)只需要 需要501个字节。所以总字节数是522,小于767.那么为什么呢 我收到了错误消息吗?
UTF8需要每个字符3个字节来存储字符串,所以在你的情况下20 + 500个字符= 20 * 3 + 500 * 3 = 1560 字节是< strong> 允许 767 字节。
UTF8的限制是767/3 = 255个字符,对于UTF8mb4,每个字符使用4个字节,它是767/4 = 191个字符。
如果您需要使用比限制更长的列,则有两种解决方案:
- 使用<!>“更便宜的<!>”;编码(每个字符需要较少字节的编码)
在我的情况下,我需要在包含SEO字符串文章的列上添加唯一索引,因为我只使用[A-z0-9\-]
字符用于SEO,我使用latin1_general_ci
,每个字符只使用一个字节,因此列的长度可以是767字节。 - 从您的列创建哈希,并仅在该
上使用唯一索引 我的另一个选择是创建另一个存储SEO的哈希列,该列将有UNIQUE
键以确保SEO值是唯一的。我还会将原始SEO列添加KEY
索引以加快查找速度。
醇>
在回答关于为什么你会得到错误信息,已经回答了许多用户在这里。我的答案是关于如何解决和使用它,因为它是。
参照从 这个链接.
- 开MySQL client(或只客户)。这是一个命令行工具。
- 它将要求您的密码,进入正确的密码。
- 选择你的数据库通过利用这个命令
use my_database_name;
数据库改变
set global innodb_large_prefix=on;
查询确定,0影响的行(0.00sec)
set global innodb_file_format=Barracuda;
查询确定,0影响的行(0.02sec)
- 去你的数据库上头文件或类似的东西,易于管理。>选择的数据库>查看表 结构 >去 操作 标签。>的变化 ROW_FORMAT 要 动态 和保存的变化。
- 去表的 结构 卡>击 唯一的 按钮。
- 完成。现在应该没有错误。
问题的这个解决方法是如果你的出口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)。
您绝对可以使用utf8mb4为VARCHAR(255)
字段添加常规索引,但会发生的情况是索引大小会自动截断为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列的字符长度超过一定长度。在<=>的情况下,该特定长度为191。
有关如何在MySQL数据库中使用长索引的更多信息,请参阅本文中的长索引部分: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database- character-set-to-utf8mb4
我做了一些检索关于这一主题最后得到了一些定义的更改
MySQL工作台6.3.7版本的图形化间阶段提供
- 开始工作台和选择的连接。
- 去管理或实例以及选择选项文件。
- 如果工作台问你许可读文件的配置以及随后允许它按确定两次。
- 在中心的地方管理的选项文件窗口。
- 去少卡和检查innodb_large_prefix如果不检查中的大部分。
- 设置innodb_default_row_format选项的价值为动态。
对于版本如下6.3.7直接选项都不可用,因此需要去命令提示
- 开始记录作为管理员。
- 去主任mysql服务器安装的大多数情况下它在 "C:\Program 文件\MySQL\MySQL Server5.7\站"的使命是 "cd\" "cd程序文件\MySQL\MySQL Server5.7\bin"。
- 现在运行命令 mysql-u用户名p databasescheema 现在,它要求对于密码的各个用户。提供的密码,进入mysql提示。
- 我们必须设置一些全球设置进入下一个接一个的命令 设置全球innodb_large_prefix=on;设置全球innodb_file_format=barracuda;设置全球innodb_file_per_table=true;
- 现在,最后我们必须改变ROW_FORMAT的需要表通过默认其紧凑,我们必须设定其为动态。
- 使用以下命令 改变表table_name ROW_FORMAT=动态;
- 做
我用以下方法解决了这个问题:
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
更改整理。您可以使用支持几乎所有
的 utf8_general_ci在创建表时,只需将utf8mb4
更改为utf8
即可解决我的问题。例如:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
到CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
。
对于laravel 5.7或5.6或5.8
要遵循的步骤
- 转到
App\Providers\AppServiceProvider.php
。 - 将此添加到顶部的提供商
use Illuminate\Support\Facades\Schema;
。 - 启动功能内部添加此
Schema::defaultStringLength(191);
醇>
所有,享受。
根据下面给出的列,这两个变量字符串列使用utf8_general_ci
排序规则(utf8
字符集隐含)。
在MySQL中,utf8mb4
charset为每个字符使用最多 3个字节。因此,它需要分配500 * 3 = 1500字节,这比MySQL允许的767字节大得多。这就是你得到这个1071错误的原因。
换句话说,您需要根据字符集的字节表示来计算字符数,因为并非每个字符集都是单字节表示(如您所设想的那样)。 MySQL中的<=>最多使用每个字符3个字节,767/3 <!>#8776; 255个字符,<=>,最多4个字节的表示,767/4 <!>#8776; 191个字符。
众所周知,MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
我发现此查询可用于检测哪些列的索引违反了最大长度:
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')
请检查sql_mode
是否类似
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
如果是,请改为
sql_mode=NO_ENGINE_SUBSTITUTION
OR
重新启动服务器,更改my.cnf文件(放下)
innodb_large_prefix=on
就我而言,当我使用linux重定向输出/输入字符备份数据库时,我遇到了这个问题。因此,我按如下所述更改语法。 PS:使用linux或mac终端。
备份(没有<!> gt;重定向)
# mysqldump -u root -p databasename -r bkp.sql
恢复(没有<!> lt;重定向)
# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql
错误<!> quot;指定密钥太长;最大密钥长度为767字节<!> quot;简单的消失了。
索引长度<!> amp; MySQL / MariaDB
Laravel默认使用 utf8mb4字符设置,其中包括支持在数据库中存储 <!>“emojis <!> <<; 。如果您运行的是早于5.7.7版本的MySQL版本或早于10.2.2版本的MariaDB,您可能需要手动配置迁移生成的默认字符串长度,以便MySQL为它们创建索引。您可以通过在 AppServiceProvider中调用 Schema :: defaultStringLength 方法进行配置:
use Illuminate\Support\Facades\Schema;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
或者,您可以为数据库启用innodb_large_prefix选项。有关如何正确启用此选项的说明,请参阅数据库的文档。
官方laravel文档中的参考: https://laravel.com/文档/ 5.7 /迁移
将抱怨索引字段的CHARSET更改为<!> quot; latin1 <!> quot;
即ALTER TABLE tbl CHANGE myfield myfield varchar(600)CHARACTER SET latin1 DEFAULT NULL;
latin1占用一个字符而不是四个
如果您正在创建以下内容:
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
由于前缀限制,将发生此错误。 767字节是5.7之前的MySQL版本中InnoDB表的规定前缀限制。 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;
要解决这个问题,这对我来说就像一个魅力。
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
如果您最近更改了innodb_log_file_size
,请尝试恢复之前有效的值。
对我来说,问题<!>#1071 - 指定密钥太长了;最大密钥长度为767字节<!> quot;通过将列大小限制为200来更改primarykey / uniquekey组合后得到解决。
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);