找回密码
 立即注册
快捷导航

[数据库] MySQL 八股文之你搞懂字符集与排序规则了么?

[复制链接]
镖师 2023-7-12 14:05:29 | 显示全部楼层
本帖最后由 镖师 于 2023-7-12 14:07 编辑

1. 字符集与编码

字符集(character set) 是某些字符的集合,为每个字符分配一个唯一的 ID,称为 “Code Point(码位或码点)”。

编码规则 是将 Code Point 转换为字节序列(即 0 和 1)的规则。

通俗地理解,就是不同的字符集规定了字符集中都包含哪些字符,而 编码规则 规定了每个字符在计算机中的 0、1 表达方式。

常用的字符集编码有:

  1. ASCII 字符编码:既是字符集,又是编码。
  2. latin1 字符编码:既是字符集,又是编码。
  3. GB2312 字符编码:既是字符集,又是编码。
  4. GBK 字符编码:既是字符集,又是编码。
  5. UTF-8:只是字符编码,对应的字符集为 Unicode。

为了便于统一管理各地区、各国家的编码规则,标准化组织用 “页码” 对众多的编码规则进行了编号,如 GBK 的页码为 956,而 UTF-8 的页码为 65001。这样,直接通过页码即可找到所需的编码规则。

1.1. ASCII 字符集

ASCII 共收录 128 个字符,包含空格、标点符号、数字、大小写字母和一些不可见字符。由于总共才 128 个字符,所以可以使用 1 个字节来进行编码。即 ASCII 既是字符集又是编码规则。我们看一些字符的编码方式:

'L' -> 01001100(十六进制:0x4C,十进制:76)
'M' -> 01001101(十六进制:0x4D,十进制:77)

1.2. ISO 8859-1 字符集

ISO 8859-1(别名 latin1) 共收录 256 个字符,在 ASCII 字符集的基础上又扩充了 128 个西欧常用字符(包括德法两国的字母),也可以使用 1 个字节来进行编码。即 ISO 8859-1 既是字符集又是编码规则。

1.3. GB2312 字符集

GB2312 是第一个汉字编码国家标准,由中国国家标准总局于 1980 年发布,1981 年 5 月 1 日开始使用。GB2312 编码共收录汉字 6763 个,其中一级汉字 3755 个,二级汉字 3008 个。同时,GB2312 编码收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682 个全角字符。即 GB2312 既是字符集,又是编码规则。

有关 GB2312 字符编码,详见 https://www.qqxiuzi.cn/zh/hanzi-gb2312-bianma.php

1.4. GBK 字符集

GBK 是对 GB2312 的补充,完全兼容 GB2312。同 GB2312 一样,GBK 也既是字符集,又是编码规则。

1.5. Unicode 字符集

Unicode(Universal Multiple-Octet Coded Character Set)是由名为 Unicode 的学术机构推出的字符集,旨在收录人类目前已知在用的所有字符, 给它们进行统一的分类和编号。但是,Unicode 只负责给字符编号,却未规定具体的编码规则。即 Unicode 只规定了字符集。
而 UTF-8, UTF-16, UTF-32 就是对 Unicode 字符集具体的编码规则。

1.5.1. UTF-8 编码

UTF-8 编码使用 变长编码 规则,用 1-4 个字节表示 Unicode 中的 1 个字符。UTF-8 编码规定:

- 最高位以 0 开头的字节,用 1 个字节表示 1 个字符,如英文字符;
- 最高位以 110 开头的字节,与其后 1 个以 10 开头的字节拼接为一个整体,即用 2 个字节表示 1 个字符;
- 最高位以 1110 开头的字节,与其后 2 个以 10 开头的字节拼接为一个整体,即用 3 个字节表示 1 个字符,如汉字。
- 最高位以 11110 开头的字节,与其后 3 个以 10 开头的字节拼接为一个整体,即用 4 个字节表示 1 个字符

MySQL 八股文之你搞懂字符集与排序规则了么?9000 作者:镖师 帖子ID:477

1.5.2. UTF-16 编码

UTF-16 编码使用 定长编码 规则,固定地使用 2 个字节来表示 Unicode 中的 1 个字符。

在 Windows 系统中,常常会同时出现 UTF-8 和 Unicode 两个编码规则。按道理,Unicode
只是字符集,不应出现在编码规则当中。原因是,微软默认将 Unicode 当作 UTF-16 来处理。

1.5.3. UTF-32 编码

UTF-32 编码使用 定长编码 规则,固定地使用 4 个字节来表示 Unicode 中的 1 个字符。直接根据 Unicode 中的字符编号对字符进行编码。优点是无需额外的解析工作,缺点是常用字符有大量的高位被 0 填充,而造成空间浪费。

2. MySQL 中的字符集与排序规则

如下所示,可通过系统表 INFORMATION_SCHEMA.CHARACTER_SETS 查看 MySQL 中支持的字符集及默认的排序规则(省略了部分不常用的字符集)。

mysql> SELECT CHARACTER_SET_NAME,DEFAULT_COLLATE_NAME,MAXLEN FROM INFORMATION_SCHEMA.CHARACTER_SETS ORDER BY 1,2;
+--------------------+----------------------+--------+
| CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | MAXLEN |
+--------------------+----------------------+--------+
| ascii              | ascii_general_ci     |      1 |
| big5               | big5_chinese_ci      |      2 |
| gb18030            | gb18030_chinese_ci   |      4 |
| gb2312             | gb2312_chinese_ci    |      2 |
| gbk                | gbk_chinese_ci       |      2 |
| latin1             | latin1_swedish_ci    |      1 |
| latin2             | latin2_general_ci    |      1 |
| latin5             | latin5_turkish_ci    |      1 |
| latin7             | latin7_general_ci    |      1 |
| utf16              | utf16_general_ci     |      4 |
| utf16le            | utf16le_general_ci   |      4 |
| utf32              | utf32_general_ci     |      4 |
| utf8               | utf8_general_ci      |      3 |
| utf8mb4            | utf8mb4_0900_ai_ci   |      4 |
+--------------------+----------------------+--------+
41 rows in set (0.00 sec)

2.1. utf8 与 utf8mb4

  1. utf8(utf8mb3)

在 MySQL 中,utf8 是 utf8mb3 的别名,是严格过的 utf8 编码。用 1-3 个字节来编码 Unicode 字符集中的 1 个字符。该编码中,不包含 Emoji 表情等特殊字符。MySQL 从 8.0.30 开始,将 utf8 名称调整为 utf8mb3,如字符集 utf8mb3 及以 utf8mb3_ 为前缀的排序规则。

  1. utf8mb4

正宗的 utf8 编码。使用 1-4 个字节来编码 Unicode 字符集中的 1 个字符,在 utf8mb3 的基础上,增加了对 Emoji 表情等特殊字符的编码支持;

2.2. 排序规则

排序规则(Collation)定义了字符集中每个字符的大小、先后顺序以及等价规则等。如在排序时,哪个字符在前、哪个字符在后、哪个字符与哪个字符相等。Collation 依赖于字符集(Character Set),比如 utf8mb4_general_ci 排序规则要求字符集需要为 utf8mb4gbk_chinese_ci 排序规则要求字符集为 gbk

若将字符看作人,Character Set 就相当于为每个字符发放一个身份证号,所有的身份证号组成了字符集。而 Collation 相当于规定在排队时,谁在前、谁在后。Collation 可以有多个,就相当于可灵活按身高、体重、年龄、出生地等维度来对每个人排序,却完全不会受到身份证号的干扰。

2.2.1. MySQL 中常用的排序规则

如下所示,可通过系统表 INFORMATION_SCHEMA.COLLATIONS 查看 MySQL 中主要字符集所支持的排序规则(省略部分不常用的规则)。

mysql> SELECT character_set_name, collation_name, is_default, pad_attribute FROM INFORMATION_SCHEMA.COLLATIONS WHERE character_set_name in ('utf8','utf8mb4','gbk','gb2312','ascii') ORDER BY 1,2;
+--------------------+----------------------------+------------+---------------+
| character_set_name | collation_name             | is_default | pad_attribute |
+--------------------+----------------------------+------------+---------------+
| ascii              | ascii_bin                  |            | PAD SPACE     |
| ascii              | ascii_general_ci           | Yes        | PAD SPACE     |
| gb2312             | gb2312_bin                 |            | PAD SPACE     |
| gb2312             | gb2312_chinese_ci          | Yes        | PAD SPACE     |
| gbk                | gbk_bin                    |            | PAD SPACE     |
| gbk                | gbk_chinese_ci             | Yes        | PAD SPACE     |
| utf8               | utf8_bin                   |            | PAD SPACE     |
| utf8               | utf8_general_ci            | Yes        | PAD SPACE     |
| utf8               | utf8_general_mysql500_ci   |            | PAD SPACE     |
| utf8               | utf8_german2_ci            |            | PAD SPACE     |
| utf8               | utf8_spanish2_ci           |            | PAD SPACE     |
| utf8               | utf8_spanish_ci            |            | PAD SPACE     |
| utf8               | utf8_unicode_520_ci        |            | PAD SPACE     |
| utf8               | utf8_unicode_ci            |            | PAD SPACE     |
| utf8mb4            | utf8mb4_0900_ai_ci         | Yes        | NO PAD        |
| utf8mb4            | utf8mb4_0900_as_ci         |            | NO PAD        |
| utf8mb4            | utf8mb4_0900_as_cs         |            | NO PAD        |
| utf8mb4            | utf8mb4_0900_bin           |            | NO PAD        |
| utf8mb4            | utf8mb4_bin                |            | PAD SPACE     |
| utf8mb4            | utf8mb4_cs_0900_ai_ci      |            | NO PAD        |
| utf8mb4            | utf8mb4_cs_0900_as_cs      |            | NO PAD        |
| utf8mb4            | utf8mb4_general_ci         |            | PAD SPACE     |
| utf8mb4            | utf8mb4_german2_ci         |            | PAD SPACE     |
| utf8mb4            | utf8mb4_spanish2_ci        |            | PAD SPACE     |
| utf8mb4            | utf8mb4_spanish_ci         |            | PAD SPACE     |
| utf8mb4            | utf8mb4_unicode_520_ci     |            | PAD SPACE     |
| utf8mb4            | utf8mb4_unicode_ci         |            | PAD SPACE     |
| utf8mb4            | utf8mb4_zh_0900_as_cs      |            | NO PAD        |
+--------------------+----------------------------+------------+---------------+
109 rows in set (0.00 sec)

排序规则名称中的关键字解释如下:

  • utf8(utf8mb3):用 1-3 个字节来编码 Unicode 字符集中的 1 个字符;MySQL 从 8.0.30 开始,将 utf8 名称调整为 utf8mb3,如字符集 utf8mb3 及以 utf8mb3_ 为前缀的排序规则。TiDB 因兼容 MySQL 5.7,所以仍延用旧的名称 utf8;
  • utf8mb4:使用 1-4 个字节来编码 Unicode 字符集中的 1 个字符,增加了对 Emoji 表情的支持;
  • _bin:二进制存储,区分大小写。如 E 与 e 不等价;
  • _cs(case sensitivity):区分大小写。如 E 与 e 不等价;
  • _ci(case insensitivity):不区分大小写。如 E 与 e 等价;
  • _as(accent sensitivity):区分音调,如 e、ē、é、ě、è 不等价;
  • _ai(accent insensitivit):不区分音调,如 e、ē、é、ě、è 等价;
  • _general:排序速度快,准确度低;
  • _unicode:排序遵循 UCA 4.0.0 规范,速度慢,准确度高;MySQL 依据 UCA(Unicode Collation Algorithm)4.0.0 实现了 xxx_unicode_ci 排序规则;
  • _520_0900:排序遵循 UCA 5.2.0、UCA 9.0.0 规范;MySQL 在实现遵循 > UCA 4.0.0 的排序规则时,在排序规则名称中包含 UCA 版本号。如,utf8_unicode_520_ci 遵循 UCA 5.2.0 规范进行排序;utf8mb4_0900_ai_ci(MySQL 8.0 引入)遵循 UCA 9.0.0 规范进行排序;
  • _chinese:按中文拼音排序,如如 ē<é<ě<è;
  • _zh:特定于中文的 Unicode 排序。类似的还有:ja 特定于日语的排序、ru 特定于俄语的排序等;

2.3. 各级别字符集与排序规则

MySQL 有 4 个级别的字符集和比较规则,分别是:

  • 服务器级别
  • 数据库级别
  • 表级别
  • 列级别
  • 字符串级别

2.3.1. 服务器级别

系统参数 动态设置 作用域 说明
character_set_server Y BOTH 用于设置服务器级别的默认字符集
collation_server Y BOTH 用于设置服务器级别的默认排序规则

可通过 SHOW GLOBAL VARIABLESSET 来查看和修改服务器级别的字符集与排序规则。

mysql> SHOW GLOBAL VARIABLES LIKE 'character_set_server';
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| character_set_server | utf8mb4 |
+----------------------+---------+
1 row in set (0.01 sec)

mysql> SHOW GLOBAL VARIABLES LIKE 'collation_server';
+------------------+--------------------+
| Variable_name    | Value              |
+------------------+--------------------+
| collation_server | utf8mb4_general_ci |
+------------------+--------------------+
1 row in set (0.00 sec)

mysql> SET PERSIST character_set_server='utf8mb3';
Query OK, 0 rows affected, 1 warning (0.00 sec)

也可在 MySQL 配置文件中,指定服务器级别的字符集与排序规则。

[mysqld]
character_set_server= utf8mb4 
collation-server = utf8mb4_general_ci

当修改了服务器级别的默认字符集后,排序规则会自动随之修改为该字符集对应的默认排序规则。

2.3.2. 数据库级别

在创建数据库时,可显式为其指定默认字符集及排序规则。也可通过 ALTER DATABASE 来变更数据库的默认字符集与排序规则。若在建库时,不显式指定字符集与排序规则,默认将继承服务器级别的设置。

mysql> CREATE DATABASE dbtest CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
mysql> ALTER DATABASE dbtest CHARACTER SET gbk COLLATE gbk_chinese_ci;

可通过只读系统参数 character_set_databasecollation_database 来查看当前数据库的默认字符集与排序规则。参数值会随着数据库的变化而变化。

mysql> use dbtest;

mysql> SHOW VARIABLES LIKE 'character_set_database';
+------------------------+---------+
| Variable_name          | Value   |
+------------------------+---------+
| character_set_database | utf8mb4 |
+------------------------+---------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'collation_database';
+--------------------+--------------------+
| Variable_name      | Value              |
+--------------------+--------------------+
| collation_database | utf8mb4_general_ci |
+--------------------+--------------------+
1 row in set (0.00 sec)

2.3.3. 表级别

在创建表时,可显式为其指定默认字符集及排序规则。也可通过 ALTER TABLE 来变更表的默认字符集与排序规则。若在建表时,未为其显式指定字符集与排序规则,则默认将继承自数据库级别的设置。

mysql> CREATE TABLE tbl01 (id int, name varchar(32)) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
mysql> ALTER TABLE tbl01 CHARACTER SET gbk COLLATE gbk_chinese_ci;

可通过 SHOW CREATE TABLE 来查看表的默认字符集与排序规则。

mysql> SHOW CREATE TABLE tbl01\G
*************************** 1. row ***************************
       Table: tbl01
Create Table: CREATE TABLE `tbl01` (
  `id` int DEFAULT NULL,
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)

2.3.4. 列级别

对于存储字符串的列,同一个表中的不同列也可有不同的字符集和排序规则。可以在创建和修改列定义的时候指定该列的字符集和排序规则。若在建表时,未为字符串列指定字符集和排序规则,则默认继承自表级别的设置。

mysql> ALTER TABLE tbl01 MODIFY name varchar(32) CHARACTER SET gbk COLLATE gbk_chinese_ci;

2.3.5. 字符串级别

SELECT 字符串 时未指定字符集及排序规则,则默认继承自系统变量 character_set_connectioncollation_connection

mysql> SELECT _utf8mb4'盛京征信' COLLATE utf8mb4_bin;
+--------------------------------------------+
| _utf8mb4'盛京征信' COLLATE utf8mb4_bin      |
+--------------------------------------------+
| 盛京征信                                    |
+--------------------------------------------+
1 row in set (0.00 sec)

3. 字符集转换

3.1. 转换过程

汉字 “我” 的 UTF-8 编码为 “0xE68891”,而其对应的 GBK 编码为 “0xCED2”。

当将汉字 “我” 的 UTF-8 编码 0xE68891 进行解码后,再按 GBK 字符集进行重编码为 0xCED2。我们将这个过程称为 字符集的转换,也就是汉字“我”从 UTF-8 字符集转换为 GBK 字符集。

可通过如下链接:http://www.mytju.com/classcode/tools/encode_utf8.asp 可查询汉字的编码。

3.2. MySQL 中的字符集转换

客户端在向 MySQL 服务器发送 SQL 请求,并从服务器获取返回结果的这个过程中,伴随着多次字符集的转换。在此过程中会用到 3 个系统参数:

系统参数 动态修改 作用域 说明
character_set_client Y Both 服务器解码客户端发送的 SQL 语句和数据时,使用的字符集。 即服务器总是假设客户端是按 character_set_client 设置的字符集来传输数据和 SQL 请求。
character_set_connection Y Both 服务器在处理客户端请求前,先将请求数据由 character_set_client 转换为 character_set_connection 字符集,再进行处理。 若表列的字符集与 character_set_connection 不一致,在处理数据时还需要再次将请求转换为表列对应的字符集。
character_set_results Y Both 服务器向客户端返回结果数据时,使用的字符集。 即服务器先将结果数据转换为 character_set_results 字符集之后,再返回给客户端。

MySQL 八股文之你搞懂字符集与排序规则了么?9145 作者:镖师 帖子ID:477

  1. 客户端使用 OS 默认的字符集将 SQL 语句及数据编码后,发送给 MySQL 服务器。如 Windows 默认字符集为 gbk,类 Unix 默认为 utf8。
  2. 服务器接收到 SQL 请求和数据后,按 character_set_client 字符集进行解码,并按 character_set_connection 字符集重新编码。
  3. 服务器执行 SQL 处理时,比对表列的字符集与 character_set_connection 是否一致。若不一致,则需将请求数据转换为表列中设置的字符集。
  4. 服务器得到执行结果后,将字符集从表列对应的字符集转换为 character_set_results 后,发送给客户端。
  5. 客户端收到服务器返回的结果后,按照客户端的默认字符集进行解码,读取内容。

3.3. 如何避免乱码

当出现如下情况,即编码与解码使用的字符集不一致时,即可出现乱码。

  • 当客户端 OS 默认字符集与 MySQL 系统参数 character_set_client 不一致时。
  • 当客户端 OS 默认字符集与 MySQL 系统参数 character_set_results 不一致时。

通常要确保 character_set_client character_set_connection character_set_results 这三个参数值与客户端使用的字符集一致,可避免出现乱码。

为配置文件 my.cnf 增加 default-character-set 选项,可统一设置 character_set_client character_set_connection character_set_results 这三个系统参数的值。

[client]
default-character-set=utf8mb4

或通过命令 SET NAMES <字符集> 统一设置会话级系统参数 character_set_client character_set_connection character_set_results 的值。

mysql> SET NAMES utf8mb4;

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

温馨提示

关于 注册码 问题

      由于近期经常大量注册机器人注册发送大量广告,本站开启免费入群领取注册码注册网站账号,注册码在群公告上贴着...

关于 注册码 问题

      由于近期经常大量注册机器人注册发送大量广告,本站开启免费入群领取注册码注册网站账号,注册码在群公告上贴着...

Archiver|手机版|小黑屋|DLSite

GMT+8, 2024-10-30 12:20

Powered by Discuz! X3.5 and PHP8

快速回复 返回顶部 返回列表