MySQL里面的utf8与utf8mb4有什么区别呢?

最近发现公司有一部分表使用的是utf8mb4字符集,之前没有用过,看起来好像有点关系,但是又说不清,看了官方文档,翻译总结为本文。

名词解释

BMP字符

Unicode采用基于平面的设计,平面有点像网络协议的分层,每层实现不同的逻辑。而Unicode的每个平面表示的字符是不同的,最基本的就是BMP(Basic Multilingual Plane),中文名称为基本多文种平面。 对应的Unicode标识范围是U+0000 - U+FFFF,根据下表可以看出对应的二进制最多占用3字节。

Unicode 和 UTF-8 之间的转换关系表(摘自维基百科)

补充字符

同理,补充字符就是除了BMP之外的一些字符,可以概括为补充平面

这些字符可能并不常见,从维基百科的第二辅助平面找到了一个汉字“𦡦”,通过下面的sql可以对比两个字符集,可以发现utf8mb3不支持这个汉字。

select _utf8mb3 '𦡦';
select _utf8mb4 '𦡦';

-- 或者用这种语法
SELECT CAST('𦡦' AS CHAR CHARACTER SET utf8);
SELECT CAST('𦡦' AS CHAR CHARACTER SET utf8mb4);

先说结论

utf8在MySQL内部是utf8mb3,顾名思义最多占用三字节,但是我们印象中的utf8最多是占用四字节的,其实MySQL的utf8是简化版的字符集,而他与四字节的utf8相差的就是上述的补充字符。

我个人理解MySQL这个样的设计是从灵活性和性能方面来考虑的,因为补充字符的应用场景有限,部分场景下使用utf8mb3就能满足使用。 如果都用utf8mb4,虽然相同字符存储空间占用一样,但是utf8mb4的排序规则应该要比utf8mb3更复杂,在处理类似排序、比较等逻辑上可能占用的资源更多。(猜测,未经实验)

如果需要补充字符,使用utf8mb4。

实际情况可根据需求酌情选择。

文档翻译

utf8

utf8又名utf8mb3,隐式对存储的字符做了限制,是3字节UTF-8 unicode编码。

utf8mb3有如下特性:

  • 仅支持BMP字符,不支持补充字符
  • 每个多字节字符最多占用三个字节

应用如果需要存储补充字符,可使用utf8mb4。

utf8mb3与ucs2提供了完全相同的字符集。

utf8mb3能应用于CHARACTER SET子句和utf8mb3_collation_substring校对规则子句,这里的collation_substring可以是bin, czech_ci, danish_ci, esperanto_ci, estonian_ci等等,例如:

CREATE TABLE t (s1 CHAR(1) CHARACTER SET utf8mb3;
SELECT * FROM t WHERE s1 COLLATE utf8mb3_general_ci = 'x';
DECLARE x VARCHAR(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_danish_ci;
SELECT CAST('a' AS CHAR CHARACTER SET utf8) COLLATE utf8_czech_ci;

MySQL内部会立刻转换utf8mb3为utf8,所以在下面的语句中看到的都是utf8utf8_collation_substring

SHOW CREATE TABLE t1;
SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS;
SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS;

除了上面的应用,还可以用在其他位置,例如:

mysqld --character-set-server=utf8mb3
SET NAMES 'utf8mb3'; /* 其他有类似效果的SET语句 */
SELECT _utf8mb3 'a';

utf8mb4

utf8mb4,4字节UTF-8 unicode编码。

utf8mb4有一下特性:

  • 支持BMP和补充字符
  • 每个多字节字符最多占用四个字节

对比utf8mb3字符集:

  • 对于BMP字符,utf8mb3和utf8mb4具有相同的存储特征:相同的字面值,相同的编码,相同的大小
  • 对于补充字符,utf8mb4需要四字节存储,而utf8mb3不能存储这些字符。当要把utf8mb3的列转换为utf8mb4的时候,不需要担心补充字符的转换,因为根本就不存在(译注:向utf8mb3字符集的列写入补充字符时,sql会提示越界,无法写入)

utf8mb4是utf8mb3的超集(译注:转换操作类似编程语言中的类型转换,小转大),如下拼接的操作,结果是utf8mb4字符集和utf8mb4_col列的校对规则:

SELECT CONCAT(utf8mb3_col, utf8mb4_col);

同样的,下面的where子句的比较也是按照utf8mb4_col列的校对规则进行:

SELECT * FROM utf8mb3_tbl, utf8mb4_tbl
WHERE utf8mb3_tbl.utf8mb3_col = utf8mb4_tbl.utf8mb4_col;

参考链接

(完)