- 首先了解什么是Unicode:
Unicode是一种信息技术(IT)标准,用于对世界上大多数书写系统中表示的文本进行一致的编码,表示和处理。
大致意思就是Unicode对英文字符、符号、汉字、表情符号制定的统一数字码表,例如:
大写字母 M :二进制是 1001101,十进制是 77,十六进制是 4d
汉字 前:二进制是101001001001101,十进制是21069,十六进制是524d
但是计算机不能直接拿这个数字码表来进行字符存储,因为里面没有表示截断的部分,计算机不知道该什么时候一个字符表示完了。
计算机是字节存储(就是八位二进制)
M 如果直接存储就是: 01001101
前 如果直接存储就是:01010010 01001101
可以看到 M 和 前 最后的码表是一样的,计算机无法判断:是 M 或者是 前 的后半段。
- UTF-8 就是对 Unicode 中的所有字符进行编码的一种格式。它的编码规范是:
一、对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
二、对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的有效 Unicode 码。
对应出来的规范表格(x是Unicode有效码):
字节数 | 第一个码点(十六进制) | 最后的码点(十六进制) | 字节一 | 字节二 | 字节三 | 字节四 |
---|---|---|---|---|---|---|
1 | U+0000 | U+007F | 0xxxxxxx | |||
2 | U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
3 | U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
4 | U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
那么按照上面的表格,前 十六进制:524d,属于0800-FFFF,表示为3个字节。UTF-8应该是(从后往前转换、高位不足补零):
11100101 10001001 10001101
- 基础知识有了,那么MySQL中的 utf8 和 utf8mb4 有什么区别
其实 MySQL中的utf8 是 utf8mb3,只能表示1-3个字节,因为当时的字符还没有这么多,MySQL的开发者认为3个字节足够表示所有Unicode字符做的反向优化。
如今emoji表情和其他字符的加入,使得 utf8mb3 不够表示,所有添加了utf8mb4,遵守 UTF-8 编码格式,可以表示4个字节的字符。
由于 MySQL中的 utf8 名称已经被 utf8mb3 占用,所以只能将真正的遵守UTF-8编码格式字符集起名为 utf8mb4。
现在MySQL8.0已经默认使用utf8mb4,官网也声明:
utf8mb3 已经弃用,会在将来的版本进行删除。现如今的 utf8 含义混淆,请显式指定为 utf8mb4
- general_ci 、 unicode_ci 和 unicode_520_ci 的区别:
这几种都是MySQL中 字符集编码的排序算法。
unicode_ci是遵守的Unicode组织的4.0.0归类算法排序(有一部分没有实现:一些越南语等小语种排序) Unicode UCA 权重排名4.0.0版本
unicode_520_ci 则是基于 5.2.0 新版本实现。还有 utf8mb4_0900_ai_ci 是基于更高的 9.0.0版本实现。
general_ci 则是在 unicode_ci 排序上做了一定优化,排序效率提高了一点(?十分之一左右)。只支持单字符对比排序。
例如:
在德语中 ß 书写为 ss。
unicode_ci 只有 ß = ss,单个 s 和 ß 是不同的。
general_ci 做了优化,只支持单字符比较,但是又需要 对 ß 进行排序,所以结果是:ß = s
在StackOverflow中推荐是使用 unicode_ci,因为general_ci的效率提升有限。
而且推荐使用最新的 utf8mb4_0900_ai_ci ,因为Unicode组织也不是吃白饭的。
我认为的话,在国内环境下还是使用 general_ci,对于项目经理来说,他一定会放大 unicode_ci 10%性能的严重性,而且字符排序的准确度也没有那么重要。
参考资料:
1.MySQL官网:MySQL 8.0参考手册:Unicode字符集
2.Wiki:德语中的ß
3.StackOverflow:general_ci 和 unicode_ci
4.Wiki:Unicode
5.Wiki:UTF-8