当我执行以下命令:

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


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

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

在回答关于为什么你会得到错误信息,已经回答了许多用户在这里。我的答案是关于如何解决和使用它,因为它是。

参照从 这个链接.

  1. 开MySQL client(或只客户)。这是一个命令行工具。
  2. 它将要求您的密码,进入正确的密码。
  3. 选择你的数据库通过利用这个命令 use my_database_name;

数据库改变

  1. set global innodb_large_prefix=on;

查询确定,0影响的行(0.00sec)

  1. set global innodb_file_format=Barracuda;

查询确定,0影响的行(0.02sec)

  1. 去你的数据库上头文件或类似的东西,易于管理。>选择的数据库>查看表 结构 >去 操作 标签。>的变化 ROW_FORMAT动态 和保存的变化。
  2. 去表的 结构 卡>击 唯一的 按钮。
  3. 完成。现在应该没有错误。

问题的这个解决方法是如果你的出口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版本的图形化间阶段提供

  1. 开始工作台和选择的连接。
  2. 去管理或实例以及选择选项文件。
  3. 如果工作台问你许可读文件的配置以及随后允许它按确定两次。
  4. 在中心的地方管理的选项文件窗口。
  5. 去少卡和检查innodb_large_prefix如果不检查中的大部分。
  6. 设置innodb_default_row_format选项的价值为动态。

对于版本如下6.3.7直接选项都不可用,因此需要去命令提示

  1. 开始记录作为管理员。
  2. 去主任mysql服务器安装的大多数情况下它在 "C:\Program 文件\MySQL\MySQL Server5.7\站"的使命是 "cd\" "cd程序文件\MySQL\MySQL Server5.7\bin"。
  3. 现在运行命令 mysql-u用户名p databasescheema 现在,它要求对于密码的各个用户。提供的密码,进入mysql提示。
  4. 我们必须设置一些全球设置进入下一个接一个的命令 设置全球innodb_large_prefix=on;设置全球innodb_file_format=barracuda;设置全球innodb_file_per_table=true;
  5. 现在,最后我们必须改变ROW_FORMAT的需要表通过默认其紧凑,我们必须设定其为动态。
  6. 使用以下命令 改变表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

要遵循的步骤

  1. 转到App\Providers\AppServiceProvider.php
  2. 将此添加到顶部的提供商use Illuminate\Support\Facades\Schema;
  3. 启动功能内部添加此Schema::defaultStringLength(191);
  4. 所有,享受。

根据下面给出的列,这两个变量字符串列使用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)
);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top