在数据库配置方面,应该在UTF-8上使用Latin-1吗?


65

我们在我工作的公司中使用MySQL,并使用Ruby on Rails构建面向客户端和内部的应用程序。

当我开始在这里工作时,遇到了一个以前从未遇到过的问题。生产服务器上的数据库设置为Latin-1,这意味着只要有用户输入,用户在其中复制和粘贴UTF-8字符,MySQL gem就会引发异常。

我的老板称这些为“坏字符”,因为它们大多数是不可打印的字符,并说我们需要将它们去除。我找到了几种方法来完成此操作,但是最终我们遇到了需要UTF-8字符的情况。另外,这有点麻烦,特别是因为似乎我所读过的唯一解决方案是将数据库设置为UTF-8(对我来说很有意义)。

我听到的坚持使用Latin-1的唯一论点是,允许不可打印的UTF-8字符可能会使MySQL中的文本/全文搜索混乱。这是真的吗?

还有其他原因使人应该在UTF-8上使用Latin-1吗?据我了解,它是卓越的,并且变得越来越普遍。


4
@jon LATIN-1 不是特定于英语的。如果我没有记错的话,西班牙语和法语都很好。
Darkhogg

4
@Darkhog:Latin1确实不是特定于英语的,但实际上仅限于西欧字母。
Bart van Ingen Schenau,2015年

16
在现代系统中使用Latin 1而不是UTF-8唯一可能的好处是破坏活动。当然,这只是对破坏者的利益,对他们的忠诚者而言,对系统的所有者或开发者而言,都不是。
乔恩·汉娜

13
太糟糕了,您的数据库将无法保存欧元符号,甚至无法保存我的名字(דותן)。
dotancohen 2015年

20
用户“复制并粘贴”非拉丁1字符?不要将unicode当作只顽皮的书呆子关心的无关紧要的琐事。我们中很多人会定期输入不适合拉丁文1的字符-我听说很多人说非欧洲语言,甚至是♥
Eevee

Answers:


131

Unicode当然很困难,并且UTF-8编码有几个不方便的属性。但是,UTF-8已成为网络上的实际标准编码,超过了ASCII,Latin-1,UCS-2和UTF-16。只需使用UTF-8无处不在

支持Unicode的最重要原因是,您不应对用户输入进行不必要的假设。我不知道您的域名是什么,但是诸如希伯来语用户名,有关中国的博客文章,带有表情符号的评论或诸如“ this”之类的样式简洁的文字之类的东西都应该是可能的...哦,那些在印刷上正确的引号(“”而不是""),全角破折号和省略号,它们是英文文本中的常用字符,但ASCII或Latin-1不支持。因此,不支持其他脚本不仅会给您其他文化带来很大的麻烦,而且坚持使用Latin-1甚至无法让您编写适当的英语。

Unicode只允许“坏字符”的说法是错误的。是的,文本真的很复杂,Unicode不会对您隐藏。您的老板可能正在考虑组成字符,其中一个基本代码点(例如a,其后的代码点修改了该代码点,例如代表变音符号以形成一个视觉字符,例如)á。如果您进行某种归一化,那么在尝试进行搜索时并不会真正影响您的工作。例如,您可以将所有文本存储为NFC形式,如果有的话,可以将此类合成折叠为它们的预先合成形式。搜索时,您还可以从文本中删除所有组成字符,但这可能会在某些语言中极大地改变其含义。

Unicode还添加了许多不可打印的字符-但即使是ASCII也会加载很多字符。您会在字符串中间处理NUL吗?0x1C,“文件分隔符”怎么样?我从未见过其中的一半。Latin-1添加了一个软连字符,指示出现断字的机会,但否则看不见。这还会破坏您的全文搜索吗?换句话说,即使您认为ASCII码和Latin-1都是可打印的文本,也可以完全中断输入!


8
从数据库的角度来看,在文本类型字段(text / varchar / char / etc。)中不允许/不应允许其中某些字符。MySQL 确实允许在这些数据类型使用空字符,但其他数据库(如PostgreSQL)则不允许。如果您希望能够存储这样的字符,则应该使用BLOB(MySQL)或BYTEA(PostgreSQL)。
cimmanon 2015年

15
“坚持使用Latin-1甚至不能让您写正确的英语”,这是一件好事,否则unicode会更难以抵抗。;-)
Deduplicator

3
@PaŭloEbermann嵌入的NUL字符表示您的数据是二进制blob,而不仅仅是字符串。NUL是一个奇怪的示例,因为我相信UTF-8避免将\0字节用作多字节编码的一部分,以确保不识别UTF8的代码不会在字符串中间停止。
彼得·科德斯

7
所有unicode字符都是可打印的-您只需要正确的字体即可:-)
James Anderson

4
@JamesAnderson字体然后将是错误的和损坏的。en.wikipedia.org/wiki/Unicode_control_characters
djechlin

62

我认为,除了技术问题之外,您的老板可能没有时间跟上最新标准。

由于他的立场并非完全过时,只是过时,请在讨论此事时尊重他的立场(您需要记住进行讨论,而不是争论),并尝试解决他对UTF-8的担忧。我怀疑根本问题不是技术问题,可能需要某种程度的软技能谈判。


6
我不能再批准了。实际上,我感到遗憾的是,在我自己的回答中,我完全忽略了“人的一面”,在这一问题上,这很重要。希望我能
投票

2
调用latin-1以外的所有内容,bad character并认为这些都non-printable属于just out-dated您?
njzk2'2

2
真正的问题是,“这是我们要处理的技术问题吗?” 我不认为OP的老板去上学并受过这样的教导,或者阅读一些技术手册/期刊并得出结论。我不认为该解决方案严格来说是一种技术解决方案。具有讽刺意味的是,该评论恰恰表明了问题的核心。如果处理不当,解决此问题可能会非常令人反感。
尼尔森

49

我们哪个是对的?

从前,你的老板是。但是随着时间的流逝,情况发生了变化。如今,您可以了(但在竞选老板之前,请务必也阅读Nelson的回答)。

MySQL的旧版本以及几乎所有版本的旧版本,与较旧的Latin1 / ISO-8859-1(5)相比,对UTF8的处理要好得多。

有一个原因可以解释为什么UTF8已被创建,发展和推广到几乎所有地方:如果实施得当,它会更好。由于Latin1字符为8位,而UTF8字符的长度可能为8至32位,因此存在一些性能和存储问题。因此,在计划时,VARCHAR您需要考虑到这一点。而且您的搜索例程将稍慢一些。他们将能够做更多的事情(例如,具有重音敏感度的搜索或不进行重音搜索。如果不进行大量工作就无法在Latin1中进行搜索),但是它们花费更多时间。

但另一方面,存储价格便宜,文件大小的实际开销不到2-3%,计算能力也很便宜,并且符合摩尔定律也越来越便宜;而您的时间客户的期望肯定不是

如果您是开发此类工具的人,则可能需要担心搜索工具等。但是你可能不是。您使用这些工具;即使是那些昨天(不像以前的MySQL完全不兼容)不完全兼容UTF8的代码,也已经成为今天或不久之后(例如支持utf8mb4的MySQL)。

因此,通过以正确的方式精心计划和实施UTF8(事后不要将其放在Latin1上),您可以获得的代码可以很好地适应未来的发展,如果您打算与任何亚洲国家/地区开展业务,那么这是非常好的事情。如果您没有这样的计划,其他人也会有,这些人可能是您的客户,供应商或合作伙伴。

因此,当他们开始向您发送UTF8数据时,您将必须设置一个复杂的thingamajig来回转换为Latin1,并处理无法解决的情况。

当您考虑预算中针对邪恶的mojibake忍者的几次小冲突的成本,并考虑到它们不会消失时(如您已经发现的那样),那么您会意识到使用UTF8不仅更简单,而且会便宜的为好。


4

在某些情况下,仅将字符集限制为ASCII才有意义,这是因为选择字段有限,例如状态字段,因为您严格控制可能存在的值以及对外部系统的外键/引用,因为几乎没有任何理由除了字母数字字符和一些符号外,它们都不能包含其他任何内容。

对于其他任何文本,只需使用UTF-8。


2
MySQL没有枚举吗?
raptortech97

2
并且由于ASCII是UTF8的子集,因此即使使用UTF8也是如此。
RemcoGerlich 2015年

@RemcoGerlich:我不同意您可以使用UTF8。在我看来,外部引用不是文本,而是不透明的字节序列。除了符号方便之外,它们没有字符集。如果字节序列在某些字符集中具有解释,则它是外部系统的域或应用程序的域,而不是数据库的域。
Lie Ryan

3
@LieRyan:我明白了这一点,但是那也不应该是ASCII,可能是某种二进制blob格式。
RemcoGerlich 2015年

3

首先,答案与服务器的配置无关紧要。MySQL中的字符编码可以按列配置(意味着,同一张表可以以多种编码保存字符,很容易)。也就是说,默认情况下,为无法在连接时设置正确排序规则的旧客户端(不同的硬件客户端)为cp1251配置了服务器(以及其中的许多旧数据库),但是生产中的主要数据库都使用UTF-8。

说到“浪费的空间”-您不能现实地将重要数据称为浪费,是吗?但是,存储空间的增加会有所不同,具体取决于数据所使用的语言。如果您的网站主要使用英语,则增加幅度不大(不到1%);如果使用ASCII范围以外的字符进行邮寄,则增加到100% 。甚至更多,如果您向东移动。后来的UTF-8(所谓的UTF8mb4)规范每个代码点最多允许4个字节。

对于“谁是对的”……事实是,这不仅仅是技术问题,更是一个社会问题。进行特定服务器设置可能有正当理由,但您必须了解其中的含义。但是,如果您问我,没有理由不使用UTF-8。它是统治世界上所有文本的一种。


MySQL将尝试将数据转换为数据库编码,然后再将其转换为列编码。如果您有utf8客户端,latin1数据库和utf8 columnt,则文本数据可能会丢失。
伊万·索尔采夫

伊万,这是一个完全不同的问题。字符集客户端,字符集服务器,字符集连接,字符集结果之间的交互作用是MySQL文档中的一篇长篇文章。在按列排序规则设置的情况下,“数据库排序规则”是列排序规则,它被直接转换为字符集结果,而忽略了数据库排序规则。
AnrDaemon

0

只需向他解释,UTF-8是网络流量的默认设置。而且任何用户都可以在浏览器中输入任何有效的Unicode字符。

从前端到后端一直使用utf-8 / unicode比处理utf-8-> latin-1-> utf-8导致的许多问题要容易得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.