执行以下命令时:

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

我得到了这个错误信息:

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

columnn1和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

当前回答

根据下面给出的列,这两个变量字符串列使用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

其他回答

5解决方法:

在5.7.7中提高了限制(MariaDB 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

在MySQL 5.6(以及之前的版本)中,767字节是InnoDB表的前缀限制。MyISAM表有1000字节长。在MySQL版本5.7(及以上)中,此限制已增加到3072字节。

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

一个选择是在VARCHAR字段上设置下限。

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

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

根据需要进行调整以获得要应用的键,但我想知道是否值得检查关于这个实体的数据模型,看看是否有可能进行改进,从而允许您在不触及MySQL限制的情况下实现预期的业务规则。

我在这个话题上做了一些搜索,最后得到了一些自定义更改

MySQL工作台6.3.7版本有图形界面

启动Workbench并选择连接。 转到管理或实例并选择选项文件。 如果Workbench要求您允许读取配置文件,然后按OK两次。 在中心位置的管理员选项文件窗口出现。 进入InnoDB选项卡,如果在General部分没有检查innodb_large_prefix。 设置innodb_default_row_format选项值为DYNAMIC。

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

Start CMD as administrator. Go To director where mysql server is install Most of cases its at "C:\Program Files\MySQL\MySQL Server 5.7\bin" so command is "cd \" "cd Program Files\MySQL\MySQL Server 5.7\bin". Now Run command mysql -u userName -p databasescheema Now it asked for password of respective user. Provide password and enter into mysql prompt. We have to set some global settings enter the below commands one by one set global innodb_large_prefix=on; set global innodb_file_format=barracuda; set global innodb_file_per_table=true; Now at the last we have to alter the ROW_FORMAT of required table by default its COMPACT we have to set it to DYNAMIC. use following command alter table table_name ROW_FORMAT=DYNAMIC; Done

在导入文件中用utf8替换utf8mb4。

但请注意,utf8字符集已弃用,它不支持所有的Unicode字符,例如表情符号,所以如果这样做,您将失去对Unicode的完全支持。

Laravel框架解决方案

根据Laravel 5.4。*文档;你必须在app/Providers/AppServiceProvider.php文件的引导方法中设置默认字符串长度,如下所示:

use Illuminate\Support\Facades\Schema;

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

Laravel 5.4对这个修复的解释。*文档:

Laravel uses the utf8mb4 character set by default, which includes support for storing "emojis" in the database. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure this by calling the Schema::defaultStringLength method within your AppServiceProvider. Alternatively, you may enable the innodb_large_prefix option for your database. Refer to your database's documentation for instructions on how to properly enable this option.