在MySQL中什么时候使用utf-8,什么时候使用latin1?

12

我知道MySQL默认使用的是latin1编码。显然,latin1将一个字符存储在1个字节中,而utf-8则需要3个字节 - 这是正确的吗?

我正在开发一个希望全球使用的网站。 我一定需要使用utf-8吗?还是可以使用latin1

另外,我试图将一些表从latin1更改为utf8,但遇到了这个错误: 指定键太长;最大键长度为1000字节 有谁知道解决方案吗?我真的需要解决这个问题吗?还是latin1已经足够了?

谢谢, Alex

8个回答

12

一个Latin1字符需要1个字节来存储,而一个UTF-8字符需要1到3个字节 - 这是正确的吗?

一个Latin1字符需要1个字节来存储,而一个UTF8字符需要13个字节来存储。

如果您在字符串中只使用基本的拉丁字符和标点符号(Unicode的0128),那么两种字符集将占用相同的长度。

此外,我试图将一些表从latin1更改为utf8,但我收到了这个错误:“指定的关键字太长;最大关键字长度为1000个字节”。有人知道解决方法吗? 我真的需要解决这个问题吗?或者说使用latin1就足够了吗?

如果您有一个长度为VARCHAR(334)或更长的列,MyISAM不允许您对其创建索引,因为该列可能占用超过1000个字节。

请注意,这样长度的键很少有用。您可以创建一个前缀索引,它对任何实际数据几乎同样有效。


1
假设现在我们需要索引整个列,如何最好地解决超过1000字节的列索引问题? - Pacerier
1
但这并不索引整个列。例如,如果我们想要一个唯一的、超过1k字节的列,我们可以在前200字节上使用前缀索引。然而,这个前缀索引将强制前200个字节是唯一的。我的要求并不是前200个字节必须唯一,只要整个1000字节在表中是唯一的即可,前200个字节可以相等。有什么最好的解决方案来拥有一个超过1k字节的唯一列? - Pacerier
2
@Pacerier:你是想要用于搜索还是唯一性?如果是后者,只需为字符串的MD5哈希(或任何足够唯一的哈希)建立索引。 - Quassnoi
1
由于数据超过1000字节(假设为30k字节),因此输出仅为64字节,将会出现哈希冲突。换句话说,我认为哈希解决方案不够优秀,因为我们冒着一个错误的风险,即将数据检测为唯一,即使它已经存在于表中。是否有更好的替代解决方案? - Pacerier
1
虽然在实践中发生碰撞的可能性非常小,但如果这是一个主要问题,您也可以创建多个哈希值的组合“指纹”。例如,取MD5、SHA-1和CRC32并将它们连接起来。 - defines
显示剩余2条评论

11

最起码我建议使用UTF-8。现在90%以上的数据库都支持UTF-8,因此您的数据将与其他任何数据库兼容。

如果您选择LATIN1/ISO-8859-1,则存在数据存储不正确的风险,因为它不支持国际字符... 因此您可能会遇到像图像左侧所示的问题:

enter image description here

如果您选择使用UTF-8,就不需要处理这些头疼的问题
关于您的错误,听起来您需要优化数据库。考虑这个:http://bugs.mysql.com/bug.php?id=4541#c284415 如果您提供有关表模式和列的具体信息,那会很有帮助。

4

如果您允许用户用自己的语言发布内容,并且希望来自各个国家的用户参与,那么您至少需要将包含这些内容的表切换到UTF-8 - Latin1仅覆盖ASCII和西欧字符。 如果您打算在UI中使用多种语言,则同样如此。请参见此文章以了解如何处理迁移。


2
根据我的经验,如果你计划支持阿拉伯语、俄语、亚洲语言或其他语言,那么在一开始就投资于UTF-8支持将会在以后得到回报。然而,根据你的情况,你可能可以暂时使用英语。
至于错误,你可能有一个键或索引字段超过333个字符,在MySQL中使用UTF-8编码是允许的最大值。请参考这个错误报告

这个333字符的限制有点令人困惑。:) 许多字段可以拥有超过333个字符,对吧?它是一个不能超过333个字符的数字字段吗?通常问题到底是什么?谢谢! - Genadinik
@Genadinik:你为什么想要索引整个列?对于任何真实的字符串来说,前20个字符左右就足够使索引具有选择性了。 - Quassnoi
你可能已经有一个索引或键字段,其定义为VARCHAR(1000)或类似的类型。实际上,你不应该在那么大的字段上创建索引或键,但是当转换为UTF-8时,该字段将从1000字节增加到3000字节。正如Quassnoi所述,MyISAM不允许在超过1000字节的列上创建索引。你需要查看表定义以找出是哪一列。 - Knyphe
好的,这可能是一个愚蠢的问题 :) ...但有些列必须超过1000个字符。比如用户的简介或事件描述。或者这个错误只出现在varchar(1000)的索引上(这很可能是某个地方的拼写错误)? - Genadinik
回答自己的问题 - 是的,我犯了一个错误,将键设置为varchar(1000) - 更改后解决了这个特定的错误:)谢谢大家:) - Genadinik

2
当前最佳实践是永远不要使用MySQL的utf8字符集。相反,应该使用utf8mb4,这是标准的正确实现。
有关详细信息,请参见Adam Hooper's Explanation
请注意,在utf8mb4中,字符具有可变的字节数。顾名思义,字符最多占用四个字节。对于作为utf8mb4编码的拉丁字符集中的字符,它们仍然只占用一个字节。其他字符,包括带重音符号、汉字和表情符号,需要两个、三个或四个字节来存储。
当索引包含utf8mb4列时,会出现“指定的键太长;最大键长度为1000个字节”的错误,因为索引可能超过此限制。您需要缩短一些字符列的列长度或缩短使用此语法在列上的索引长度,以确保其小于限制。

ALTER TABLE.. ADD INDEX `myIndex` ( column1(15), column2(200) );

将表格中的列column1和column2添加到名为myIndex的索引中,其中column1的长度为15,column2的长度为200。

1

由于键的最大长度为1000个字节,如果使用utf8,则将限制您最多333个字符。

然而,MySQL与Oracle在字符集方面不同。在Oracle中,您不能针对每个列使用不同的字符集,而在MySQL中可以,因此您可以将键设置为latin1,其他列设置为utf8。

最后,我相信只有已废弃的版本6.0alpha(当Sun收购MySQL时被放弃)才能容纳超出BMP(基本多语言平面)的Unicode字符。因此,即使使用UTF-8,您也无法拥有全部Unicode字符集。实际上,这仅对罕见的中文字符是一个问题,如果这真的很重要。


1
我们之前使用拉丁文作为默认语言开发了一个应用程序。但后来由于需要处理西班牙语字符,我们不得不将所有内容都改成UTF编码。虽然这并不是非常困难,但没有必要不必要地改变事情。
因此,简短的答案就是从一开始就使用UTF-8编码,这样以后就可以避免麻烦。

1
我并不是专家,但我一直理解UTF-8实际上是一个4字节宽的编码集,而不是3字节。据我了解,MySQL对utf8_unicode_ci的实现仅处理3字节宽的编码集...如果您想要完整的UTF-8 4字节字符编码,则需要在MySQL数据库/表中使用utf8mb4_unicode_ci编码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接