Mysql中“utf-8”和"utf8mb4"的区别与使用场景

如果你要存互联网emoji表情,例如昵称,聊天,就需要utf8mb4,而不是utf-8。

 

MySQL数据库的 “utf8”并不是真正概念里的 UTF-8。

首先确实utf8需要超过3个字节的长度。其次目前可见字符集都只需要3个字节,包含了所有字符。目前问题出在unicode6系列编码上,它们需要4个字节,这部分就是有名的emoji。所以,你只要不是特种编码还是unicode,且不存emoji,保证不出问题。

 

MySQL中的“utf8”编码只支持最大3字节每字符。真正的大家正在使用的UTF-8编码是应该能支持4字节每个字符。

MySQL的开发者没有修复这个bug。他们在2010年增加了一个变通的方法:一个新的字符集“utf8mb4

当然,他们并没有对外公布(可能因为这个bug有点尴尬)。现在很多指南推荐用户使用“utf8”其实都错了。

简单的说:

MySQL中的 “utf8mb4” 才是 真正意义上的“UTF-8”。

MySQL的“utf8”是个“特殊的字符编码”。这种编码很多Unicode字符保存不了。

我强烈建议MySQL和MariaDB用户使用“utf8mb4”而不是“utf8”。

编码是什么?什么是UTF-8?

Joel on Software上有一遍我最喜欢的介绍,我精简描述如下:

计算机使用0和1存储文字。比如第一段第一个字符存储为“01000011”表示“C”,计算机通过以下两个步骤选择用“C”表示:

计算机读取到“01000011”后计算出这是数字67。

计算机通过查找Unicode字符集来确认67代表的“C”。

同样的事情发生在我打字输入C的时候。

计算机通过Unicode字符集将“C” 映射为67。

计算机把67编码为“01000011”发送给web服务器。

几乎所有的程序和互联网应用使用Unicode字符集。

Unicode字符集里有超过100万个字符(“C” 和 “” 是两种不同的字符。)。UTF-32是最简单的编码方式,它在表示每个字符的时候使用32个bits。这样编码简单,但是并不实用,明显浪费了太多的空间。

UTF-8相比UTF-32更加节约空间。在UTF-8中,像“C”这样的字符占用8bits,“”这样的占用32 bits。其他字符占用16或者24 bits。如本篇这样的文章用UTF-8存储比用UTF-32节省4倍左右的空间。更小的空间占用也意味着加载速度会快上4倍。

而MySQL中的 “utf8”字符集则和其他应用行为不一样。比如根本没法表示“”。

一点关于MySQL的历史

为什么MySQL的开发者开发了一个奇怪的“utf8”。我们可以通过提交的日志来揣测一下。

MySQL从4.1版开始支持UTF-8。那是在比今天UTF-8 RFC 3629标准更早的2003年。

在此之前的UTF-8标准,RFC 2279中规定6个bytes表示一个字符。MySQL的开发者在2002.3.28编码实现了RFC 2279 。并发布了pre-pre-release 的 MySQL 4.1

然后在9月出现了一个神秘的字节调整。“UTF8 now works with up to3 byte sequences only.”

是谁提交了这次更新?为什么?我无法解答。MySQL的源码移到Git后丢失了旧的作者信息(MySQL 曾经和linux内核一样使用BitKeeper)

但是我大概能猜出来原因。

回到2002年,如果用户可以保证表中的每一行具有相同的字节数,MySQL就可以提高用户的速度。为了得到这个提升,用户就需要定义保存文字的列为“CHAR”。一个“CHAR”列总是拥有相同的字符数。如果存入的字符较少则会在最后补齐空白。如果存入的数据过多则会被抛弃多余的字符。

当MySQL的开发者第一次尝试以6字节每字符实现UTF-8时,他们意识到CHAR(1)的列会占用6字节,CHAR(2)会占用12字节,以此类推。

显而易见的是,这个没有被使用的实现方式是正确的,任何一个理解UTF-8的开发者将会认同这一点。

我的猜测是:MySQL的开发者违背了“utf8”编码去帮助那些1)试图去优化空间和速度的人,2)尝试优化空间和速度失败的人。

这是个无人获益的改动。那些想要更快性能,更小空间的得到的依然是比他们曾经使用版本更大更慢的实现,而那些想要正确的“utf8”的人得到的是个“”都存储不了的实现。

MySQL发布了这个错误的版本后,在也没有修复它:因为那样很多使用者将被迫重建他们的数据库。MySQL最终在2010年更新了一个以“utf8mb4”命名的UTF-8实现。

Why it’s so frustrating

这周我过得很操蛋。我遇到一个很难发现的bug,就因为我被“utf8”这个名字给愚弄了。而且我也不是个案,我发现几乎每篇推荐使用“utf8”的文章都错了。

“utf8”的命名在mysql依然是错的。这是个专有的实现。这造成了新的问题,而且没有解决他应该解决的问题。

 

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
UTF-8UTF-8MB4 都是用于表示字符集的标准编码,它们的主要区别在于对最长字符长度的支持以及在数据库存储方面的应用。 ### UTF-8 的特点: 1. **字符编码长度**:UTF-8 使用 1 到 4 字节来表示不同语言的文字,最短的是单字节(例如英文字符),最长的是四字节,适用于广泛的语言文字需求。 - 单个字节范围:00xxxxxx 到 0xFFxxxxxx 2. **兼容性**:由于UTF-8 的这种结构,它在许多场景下都可以提供良好的兼容性,包括文本文件、网络传输等,同时支持基本的ASCII字符集。 3. **存储效率**:对于只包含ASCII字符的数据,UTF-8 的存储效率相对较高,因为它只需要最少的字节数来存储每个字符。 ### UTF-8MB4 的特点: 1. **最大字符长度支持**:UTF-8MB4 特别设计来支持更长的字符,特别是用于文、日文和韩文这样的东亚语言。它的最大字符可以达到四个字节,这使得它可以表示更广泛的东亚语言字符集合。 - 最大字符范围:理论上可以到 `0xFDD0` (东亚扩展区) 或者 `0x10FFFF` (通用多重区间),其 `0xE0xx` 到 `0xEFxx` 范围内的代码点需要四个字节来表示。 2. **数据库优化**:在一些数据库系统(如MySQLUTF-8MB4 是默认的Unicode字符集选择之一。它不仅支持更多的字符,而且通常有专门的优化,比如在查询处理上,使其在处理复杂字符串时更加高效。 3. **存储需求**:相比UTF-8UTF-8MB4 对于包含大量特定语言字符的数据来说,可能会增加存储需求。特别是在那些高度依赖非ASCII字符的数据库表使用UTF-8MB4 可能会显著增加磁盘空间消耗。 ### 应用情景: - **网页开发**:UTF-8 广泛应用于网页内容编码,因为它的兼容性和普遍性较好。 - **数据库管理**:对于需要处理大量文或其他东亚语言文本的应用,如本地化网站、论坛或知识库,选择UTF-8MB4 可以保证更高的性能和更好的显示效果。 - **文本处理软件**:在处理涉及多种语言文本的编辑器或转换工具,往往需要支持更复杂的字符集,因此会选择使用UTF-8MB4。 总的来说,UTF-8UTF-8MB4 的选择取决于数据的特性、应用程序的需求以及资源的可用性。对于大多数通用用途的文本处理任务,UTF-8 是一个安全且高效的选项;而对于需要处理大量东亚语言文字的特定应用,则建议选用UTF-8MB4 来充分利用其字符支持能力。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值