今天突然被同事问到,MySql 里的 uft8 与 utf8mb4 究竟有什么区别,当时我也是一脸问号,因此特地去了解了一下。
字符集
uft8 与 utf8mb4 其实指的是 MySQL 中的字符集
,那到底什么是字符集
呢?
概念
很多人常常会把字符
、字符集
、字符编码
的概念混为一谈,今天我们仔细来看看。
何为字符?
字符(Charcter)是文字与符号的总称,包括文字、图形符号、数学符号等。26个英文字母属于字符,每个汉字也属于一个字符。
那么什么叫字符集?
字符集是一组抽象的字符(Charcter)组合的集合。举一个例子,所有的汉字就算一个“字符集合”, 所有的英语字母也算一个“字符集合”。 注意,我这里说它们是字符集合,而且还有双引号。是因为字符集并不简单的是字符的集合, 准确概述来说,字符集是一套符号和编码的规则。 字符集需要以某种字符编码方式来表示、存储字符。我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态。而如果用不同的0和1组合表示不同的字符就是编码。
那什么叫字符编码呢?
字符最终是以二进制形式存储在磁盘的,这也是为什么要有字符编码的原因,因为计算机最终都要以二进制形式存储,那么编码规则就是用什么样的二进制来代表这个字符。例如,我们所熟知的ASCII码表中,01000011这个二进制对应的十进制是67,它代表的就是英语字母C。准确概述来说,字符编码方式是用一个或多个字节的二进制形式表示字符集中的一个字符。每种字符集都有自己特有的编码方式,因此同一个字符,在不同字符集的编码方式下,可能会产生不同的二进制形式。
既然我们经知道了 utf8 与 utf8mb4 都是一种字符集,那两种到底有什么区别呢?
utf8
MySQL 在创立时使用的字符集就是 utf8。首先它能存储下大部分的中文汉字,对于我们正常使用肯定是绰绰有余的。
它由三个字节
组成,能组成的最大 Unicode 字符是0xffff
,也就是 Unicode 中的基本多文种平面(BMP)。
也就是说,任何不在基本多文本平面的 Unicode 字符,都无法使用 MySQL 的 utf8 字符集存储。
utf8mb4
MySQL 在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节
的 Unicode。
新增的一个字节,可以让它支持包括 Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上),和很多不常用的汉字,以及任何新增的 Unicode 字符等等。
使用
我觉得,为了获取更好的兼容性,应该总是使用 utf8mb4 而非 utf8。
对于 CHAR 类型数据,utf8mb4 会多消耗一些空间,根据 MySQL 官方建议,可以使用 VARCHAR 替代 CHAR。
排序规则
创建库的时候,我们经常会使用语句:1
CREATE DATABASE dbname DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
既然我们知道了CHARSET
是代表字符集,那么COLLATE
又代表什么呢?它代表着排序规则。
概念
MySQl的排序规则(collation),一般指对字符集中字符串之间的比较、排序制定的规则, MySLQ排序规则特征:
o 两个不同的字符集不能有相同的校对规则;
o 每个字符集有一个默认校对规则;
o 存在校对规则命名约定:以其相关的字符集名开始,中间包括一个语言名,并且以_ci(大小写不敏感)、_cs(大小写敏感)或_bin(二元)结束。
其实对于排序规则的细节问题,我们关注较少,反而对排序规则中是否涉及大小写敏感关注较多。
例如,系统使用 utf8 字符集,若使用 utf8_bin 排序规则,执行 SQL 查询时区分大小写。使用 utf8_general_ci 不区分大小写(默认的 utf8 字符集对应的校对规则是 utf8_general_ci)。
utf8_unicode_ci 与 utf8_general_ci 的区别
当前,utf8_unicode_ci 校对规则仅部分支持 Unicode 校对规则算法。一些字符还是不能支持。并且,不能完全支持组合的记号。这主要影响越南和俄罗斯的一些少数民族语言,如:Udmurt 、Tatar、Bashkir和Mari。
utf8_unicode_ci 的最主要的特色是支持扩展,即当把一个字母看作与其它字母组合相等时。例如,在德语和一些其它语言中‘ß’等于‘ss’。
utf8_general_ci 是一个遗留的校对规则,不支持扩展。它仅能够在字符之间进行逐个比较。这意味着 utf8_general_ci 校对规则进行的比较速度很快,但是与使用 utf8_unicode_ci 的校对规则相比,比较正确性较差)。
使用
对于一种语言仅当使用 utf8_unicode_ci 排序做的不好时,才执行与具体语言相关的utf8字符集 校对规则。例如,对于德语和法语,utf8_unicode_ci 工作的很好,因此不再需要为这两种语言创建特殊的 utf8 校对规则。
utf8_general_ci 也适用与德语和法语,除了‘ß’等于‘s’,而不是‘ss’之外。如果你的应用能够接受这些,那么应该使用 utf8_general_ci,因为它速度快。否则,使用 utf8_unicode_ci,因为它比较准确。
总结
想不到 DB 创建语句中的CHARSET
与 COLLATE
都有这么大的学问,码农的学习之路真的是一刻都不能停止。
有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。
https://death00.github.io/
公众号:健程之道