mysql 字符集

126 阅读4分钟

编码和字符集的关系

虽然我们平时可以在编辑器上输入各种中文英文字母,但这些都是给人读的,不是给计算机读的,其实计算机真正保存和传输数据都是以二进制0101 的格式进行的。

那么就需要有一个规则,把中文和英文字母转化为二进制,比如"debug",计算机就需要把它转化为下图这样。

debug的编码.drawio.png

其中 d 对应十六进制下的 64,它可以转换为 01 二进制的格式。

于是字母和数字就这样一一对应起来了,这就是ASCII 编码格式。

它用一个字节,也就是8位来标识字符,基础符号有 128 个,扩展符号也是 128 个。

将它能表示的所有字符,给聚在一起,这就是我们常说的ASCII 字符集

因为使用的字节数过少,因此也就只能表示下英文字母和数字

这哪里够用。

塞牙缝都不够。

于是为了标识中文,出现了GB2312的编码格式。为了标识希腊语,出现了greek编码格式,为了标识俄语,整了cp866编码格式。

这百花齐放的场面,显然不是一个爱写if else的程序员想看到的。

为了统一它们,于是出现了Unicode 字符集,它用了 2~4 个字节来表示字符,简单的字符就用 2 个字节表示,复杂的就用 3 到 4 个字节。这样理论上所有符号都能被收录进去,并且完全兼容 ASCII 码,也就是说,同样是字母 d,在 ASCII 用 64 表示,在 Unicode 里还是用 64 来表示。但unicode 本身只是个字符集,它只规定了某个字符的具体数字是多少,但并没有规定这些数字是要用几个字节去存。

如果你用UTF-32的编码格式,它有 32 位,就会用 4 个字节去存。

如果你用UTF-16的编码格式,它有 16 位,就会用 2 个字节去存。

不同的地方是 ASCII 用 1 个字节来表示,而 Unicode 下,不管使用 UTF-16 还是 UTF-32 都至少要用两个字节来表示。

比如下图,同样都是字母 d,unicode 比 ascii 至少多使用了一个字节。

unicode比ascii多使用一个字节.drawio.png 我们可以注意到,上面的 unicode 规定的字符码,放在前面的都是 0,其实用不上,但还占了个字节,有点浪费,完全能隐藏掉。如果我们能做到该隐藏时隐藏,这样就能省下不少空间,按这个思路,就是就有了UTF-8 编码

编码格式2.drawio.png

查看mysql 的字符集

show charset; show table status from {库名} like {表名}

数据库支持哪些字符集.png

utf8 和 utf8mb4 的区别

注意下面的内容非常容易晕,大家请放慢阅读速度,关注下 utf 和 8 之间有没有横杠"-"。

上面提到 utf-8 编码是 unicode 字符集的众多编码中的一种,utf-8 也一样可以表示所有字符,为了避免混淆,我在后面叫它大 utf8

而从上面 mysql 支持的字符集的图里,我们看到了 utf8 和 utf8mb4。

先说utf8mb4编码,mb4 就是most bytes 4的意思,从上图最右边的Maxlen可以看到,它最大支持用4 个字节来表示字符,它几乎可以用来表示目前已知的所有的字符。

再说 mysql 字符集里的utf8,它是数据库的默认字符集。但注意,此 utf8 非彼 utf-8,我们叫它小 utf8字符集。

注意,这里的小 utf8和上面提到的大 utf8,并不是一回事。

为什么这么说,因为从 Maxlen 可以看出,它最多支持用 3 个字节去表示字符,按 utf8mb4 的命名方式,准确点应该叫它utf8mb3

它就像是阉割版的 utf8mb4,只支持部分字符。比如 emoji 表情,它就不支持。

查看字符集排序规则

show collation where charset = {charset}