MySQL VARCHAR(255) UTF8 对于键来说太长,但最大长度为 1000 字节

发布于 2024-11-10 06:49:07 字数 752 浏览 2 评论 0原文

我知道对此有很多疑问,但我认为我的数学是正确的。

  • MySQL 为每个 UTF8 字符保留 3 个字节。
  • MyISAM 允许密钥长度为 1000 字节。
  • 我的 UTF8 VARCHAR(255) 应该255 * 3 = 765 字节

除非 UNQUE 需要每个条目额外 200+ 字节,否则为什么这不起作用?

mysql> ALTER TABLE entry ADD UNIQUE INDEX (name(255));
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes

我能做些什么吗?

编辑:

事实证明限制是 ​​250。对于唯一索引,字符似乎算作 4 个字节,但我不知道为什么。

编辑2:

谢谢Vladislav Vaintroub,字符集确实是utf8mb4。这就解开了谜团。我没有看到任何有关此更改的文档。

我猜测它通过隐式截断字段来构建非唯一索引,这对于唯一索引来说是不可接受的,因此它拒绝。

如果您重新输入评论作为答案,我很乐意接受。

解决方案:指定utf8,而不是utf8mb4(MySQL Admin不允许这样做,所以手动创建表)

I know there have been plenty of questions about this, but I think my math is right.

  • MySQL reserves 3 bytes per UTF8 character.
  • MyISAM allows keys of length 1000 bytes.
  • My UTF8 VARCHAR(255) should be 255 * 3 = 765 bytes

Unless UNQUE requires an extra 200+ bytes per entry, why doesn't this work?

mysql> ALTER TABLE entry ADD UNIQUE INDEX (name(255));
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes

Is there anything I can do about this?

EDIT:

It turns out the limit is 250. It seems chars count as 4 bytes for unique indices, but I don't know why.

EDIT 2:

Thanks Vladislav Vaintroub, the charset is indeed utf8mb4. That solves the mystery. I hadn't seen any documentation on this change.

I'm guessing it builds the non unique index by implicitly truncating the field, which is unacceptable for unique indices so it refuses.

If you re-enter your comment as an answer I'd be happy to accept it.

Solution: Specify utf8, not utf8mb4 (MySQL Admin doesn't allow this, so create the table manually)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦毁影碎の 2024-11-17 06:49:07

如果您使用 utf8mb4,并且 varchar 列上有长度超过 191 个字符的唯一索引,则需要打开 innodb_large_prefix 以允许索引中包含更大的列,因为 utf8mb4 需要比 utf8 或 latin1 更多的存储空间。将以下内容添加到您的 my.cnf 文件中。

[mysqld]
innodb_file_format=barracuda
innodb_file_per_table=1
innodb_large_prefix=1
init_connect='SET collation_connection = utf8mb4_unicode_ci; SET NAMES utf8mb4'
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

有关原因和未来的更多信息,请参阅 MySQL 5.7 文档

如果启用了innodb_large_prefix(MySQL 5.7.7中的默认值),
对于使用的 InnoDB 表,索引键前缀限制为 3072 字节
动态或压缩行格式。如果 innodb_large_prefix 被禁用,
对于任何行格式的表,索引键前缀限制为 767 字节。

innodb_large_prefix 在 MySQL 5.7.7 中已弃用并将被删除
在未来的版本中。 innodb_large_prefix是在MySQL 5.5中引入的
禁用大索引键前缀以与早期版本兼容
不支持大索引键前缀的 InnoDB 版本。

综上所述,该限制只是为了兼容性,在未来的版本中将会增加。

If you're using utf8mb4, and you have unique indexes on varchar columns that are greater than 191 characters in length, you'll need to turn on innodb_large_prefix to allow for larger columns in indexes, because utf8mb4 requires more storage space than utf8 or latin1. Add the following to your my.cnf file.

[mysqld]
innodb_file_format=barracuda
innodb_file_per_table=1
innodb_large_prefix=1
init_connect='SET collation_connection = utf8mb4_unicode_ci; SET NAMES utf8mb4'
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

More info about the why and future from MySQL 5.7 documentation:

If innodb_large_prefix is enabled (the default in MySQL 5.7.7), the
index key prefix limit is 3072 bytes for InnoDB tables that use
DYNAMIC or COMPRESSED row format. If innodb_large_prefix is disabled,
the index key prefix limit is 767 bytes for tables of any row format.

innodb_large_prefix is deprecated in MySQL 5.7.7 and will be removed
in a future release. innodb_large_prefix was introduced in MySQL 5.5
to disable large index key prefixes for compatibility with earlier
versions of InnoDB that do not support large index key prefixes.

To sum up, the limit is only there for compatibility and will be increased in future versions.

只有一腔孤勇 2024-11-17 06:49:07

MySQL 保留 UTF8 字段的最大大小为 4 个字节,因此这就是您突破 1000 字节限制的原因。我的建议是创建小于 255 的 varchar 或在不使用 UTF8 的情况下创建它。

这两种解决方案可能都不适合您,或者您可能已经尝试过了。

我能想到的唯一其他解决方案是将列拆分为 2 个小列,并在这两个字段上创建唯一索引,但我相信您会得到与上面相同的错误。

由于您可能需要 UTF8,因此我会认真考虑将 varchar(255) 列减少到 250(或 249)以使其正常工作。

MySQL reserves the max amount for a UTF8 field which is 4 bytes, so that is why you are blowing past the 1000 byte limit. My recommendation is to create the varchar at less than 255 or create it without UTF8.

Both of those solutions are probably not right for you or you would have already tried that.

The only other solution I can think of is to split the column into 2 small columns and create an unique index on both of those fields, but I believe that you would get the same error as above.

Since you probably need UTF8, I would seriously look at reducing the varchar(255) column down a little to 250 (or 249) to make this work.

可爱暴击 2024-11-17 06:49:07

任何确实需要更大密钥长度的人都应该查看 innodb_large_prefix

访问 http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_large_prefix

Anyone who does need a larger key length should look at innodb_large_prefix

visit http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_large_prefix

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文