当我执行以下命令时:
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
答案 0 :(得分:396)
767字节是MySQL版本5.6(以及之前版本)中InnoDB表的stated prefix limitation。 MyISAM表的长度为1,000字节。在MySQL 5.7及更高版本中,此限制已增加到3072字节。
您还必须注意,如果在大字符或varchar字段上设置了一个索引,该字段为utf8mb4编码,则必须将最大索引前缀长度767字节(或3072字节)除以4,结果为191。这是因为utf8mb4字符的最大长度是四个字节。对于utf8字符,它将是三个字节,导致最大索引前缀长度为254。
您可以选择在VARCHAR字段上设置下限。
另一个选项(根据response to this issue)是获取列的子集而不是整个数量,即:
ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );
调整,因为你需要获取密钥才能应用,但我想知道是否值得查看有关此实体的数据模型,看看是否有改进可以让你实现预期的业务规则而不需要MySQL限制。
答案 1 :(得分:383)
如果有任何人遇到INNODB / Utf-8尝试在UNIQUE
字段上添加VARCHAR(256)
索引的问题,请将其切换为VARCHAR(255)
。似乎255是限制。
答案 2 :(得分:276)
当你达到极限时。设置以下内容。
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
答案 3 :(得分:145)
MySQL假定字符串中每个字符的字节数最差。对于MySQL'utf8'编码,每个字符3个字节,因为该编码不允许超出U+FFFF
的字符。对于MySQL的'utf8mb4'编码,它是每个字符4个字节,因为这就是MySQL所谓的实际UTF-8。
假设你使用'utf8',你的第一列将占据索引的60个字节,而你的第二列将占用1500个。
答案 4 :(得分:46)
在查询之前运行此查询:
SET @@global.innodb_large_prefix = 1;
这会将限制提高到3072 bytes
。
答案 5 :(得分:37)
您使用的字符编码是什么?某些字符集(如UTF-16等)每个字符使用多个字节。
答案 6 :(得分:31)
Laravel Framework解决方案
根据Laravel 5.4.* documentation;您必须在boot
文件的app/Providers/AppServiceProvider.php
方法中设置默认字符串长度,如下所示:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
此修补程序的说明,由Laravel 5.4.* documentation:
提供Laravel默认使用
utf8mb4
字符集,其中包括支持存储" emojis"在数据库中。如果您运行的是早于5.7.7版本的MySQL版本或早于10.2.2版本的MariaDB,您可能需要手动配置迁移生成的默认字符串长度,以便MySQL为它们创建索引。您可以通过调用Schema::defaultStringLength
中的AppServiceProvider
方法进行配置。或者,您可以为您启用
innodb_large_prefix
选项 数据库。有关说明,请参阅数据库的文档 如何正确启用此选项。
答案 7 :(得分:22)
我认为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个字符。
[A-z0-9\-]
字符用于搜索引擎优化,我使用latin1_general_ci
每个字符只使用一个字节,所以列可以有长度为767字节。 UNIQUE
密钥以确保SEO值是唯一的。我还会将KEY
索引添加到原始SEO列中以加快查找速度。答案 8 :(得分:18)
许多用户已经回答了有关您收到错误消息的原因的答案。我的答案是关于如何修复和使用它。
请参阅this link。
use my_database_name;
数据库已更改
set global innodb_large_prefix=on;
查询OK,0行受影响(0.00秒)
set global innodb_file_format=Barracuda;
查询OK,0行受影响(0.02秒)
此修复的问题是如果将db导出到另一台服务器(例如从localhost导出到真实主机),并且您无法在该服务器中使用MySQL命令行。你无法在那里工作。
答案 9 :(得分:17)
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字节。
答案 10 :(得分:15)
你可以添加长列md5的列
答案 11 :(得分:11)
尝试使用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个长度字段。
答案 12 :(得分:8)
这是我原来的答案:
我只是丢弃数据库并重新创建,错误消失了:
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
答案 13 :(得分:6)
我对这个主题进行了一些搜索,最后得到了一些自定义更改
对于MySQL工作台6.3.7版本可以使用图形化阶段
对于6.3.7以下的版本,直接选项不可用,因此需要使用命令提示符
答案 14 :(得分:6)
我用以下方法解决了这个问题:
varchar(200)
替换为
varchar(191)
所有超过200的varchar用191替换它们或设置它们的文本。
答案 15 :(得分:5)
更改整理。您可以使用支持几乎所有
的 utf8_general_ci答案 16 :(得分:5)
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
答案 17 :(得分:3)
仅在创建表时将utf8mb4
更改为utf8
就解决了我的问题。例如:CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
至CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
。
答案 18 :(得分:2)
根据下面给出的列,这两个变量字符串列使用utf8_general_ci
校对(隐含了utf8
字符集)。
在MySQL中,utf8
字符集为每个字符使用最多 3字节。因此,它需要分配500 * 3 = 1500字节,这比MySQL允许的767字节大得多。这就是你收到这个1071错误的原因。
换句话说,您需要根据字符集的字节表示来计算字符数,因为不是每个字符集都是单字节表示(如您所设想的那样)。 MySQL中的utf8
每个字符最多使用3个字节,767 /3≈255个字符,utf8mb4
最多使用4个字节的表示,767 /4≈191个字符。
它也知道MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
答案 19 :(得分:2)
这解决了我的问题
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
答案 20 :(得分:2)
对于laravel 5.7或5.6
要遵循的步骤
App\Providers\AppServiceProvider.php
。use Illuminate\Support\Facades\Schema;
中。Schema::defaultStringLength(191);
所有,享受。
答案 21 :(得分:1)
就我而言,当我使用linux重定向输出/输入字符备份数据库时,我遇到了这个问题。因此,我按如下所述更改语法。 PS:使用linux或mac终端。
备份(没有&gt;重定向)
host $1 | cut -d' ' -f5
恢复(没有&lt;重定向)
# mysqldump -u root -p databasename -r bkp.sql
错误&#34;指定密钥太长;最大密钥长度为767字节&#34;简单的消失了。
答案 22 :(得分: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选项。请参阅数据库的文档,以获取有关如何正确启用此选项的说明。
laravel官方文档参考: https://laravel.com/docs/5.7/migrations
答案 23 :(得分:1)
由于前缀限制,将发生此错误。在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;
答案 24 :(得分: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')
答案 25 :(得分:1)
请检查sql_mode
是否类似
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
如果是,请改为
sql_mode=NO_ENGINE_SUBSTITUTION
OR
重新启动服务器,更改my.cnf文件(放下)
innodb_large_prefix=on
答案 26 :(得分:0)
将抱怨索引字段的CHARSET更改为“latin1”
即ALTER TABLE tbl CHANGE myfield myfield varchar(600)CHARACTER SET latin1 DEFAULT NULL;
latin1占用一个字符而不是四个
答案 27 :(得分: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
答案 28 :(得分:0)
答案 29 :(得分:0)
我从varchar更改为nvarchar,对我有用。
答案 30 :(得分:0)
MySQL 有最大密钥长度限制。
这些以字节为单位!因此,一个 UTF-8 字符可能需要超过一个字节才能存储到密钥中。
因此,您只有两种直接的解决方案:
FULL TEXT
搜索 - 文本中的所有内容都可以搜索,其方式类似于 ElasticSearch如果您要创建表,请使用以下语法为某些字段的前 255 个字符建立索引:KEY
sometextkey (
SomeText(255))
。像这样:
CREATE TABLE `MyTable` (
`id` int(11) NOT NULL auto_increment,
`SomeText` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `sometextkey` (`SomeText`(255))
);
如果您已经拥有该表,那么您可以向字段添加唯一键:ADD UNIQUE(
ConfigValue(20));
。像这样:
ALTER TABLE
MyTable
ADD UNIQUE(`ConfigValue`(20));
如果字段名称不是保留的 MySQL keyword,则字段名称周围不需要反引号 (```)。
全文搜索将允许您搜索 TEXT
字段的整个值。如果您使用 NATURAL LANGUAGE MODE
,它将进行全词匹配,如果您使用其他模式之一,它将进行部分词匹配。在此处查看有关 FullText 选项的更多信息:Dev.MySQL.com
用文本创建表格,并添加全文索引...
ALTER TABLE
MyTable
ADD FULLTEXT INDEX
`SomeTextKey` (`SomeTextField` DESC);
然后像这样搜索你的桌子......
SELECT
MyTable.id, MyTable.Title,
MATCH
(MyTable.Text)
AGAINST
('foobar' IN NATURAL LANGUAGE MODE) AS score
FROM
MyTable
HAVING
score > 0
ORDER BY
score DESC;
答案 31 :(得分:-1)
对我来说,通过将列大小限制为200来更改primarykey / uniquekey组合后,解决了“#1071 - 指定密钥太长;最大密钥长度为767字节”的问题。
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
答案 32 :(得分:-1)
我对这个问题的解决方法是添加一个选项作为第三个参数:字符集
queryInterface.createTable(
tableName,
{ /*... columns*/ },
{ charset: 'utf8' }
)
否则,sequelize会将表创建为 utf8mb4 。
答案 33 :(得分:-1)
要解决此问题,这对我来说就像一种魅力。
ALTER DATABASE dbname CHARACTER SET utf8 COLLATE utf8_general_ci;
答案 34 :(得分:-1)
如果您最近更改了innodb_log_file_size
,请尝试恢复之前有效的值。
答案 35 :(得分:-3)
如果您运行Laravel(laravel现在默认为4字节Unicode导致这一点),您可以通过更改下一行来解决此问题 来自
的config / database.php'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
 到
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',