MySQL字符集

**计算机只能识别二进制代码,为了让计算机也能处理文字信息,需要对每个文字符号进行编码,以便于计算机识别和处理,这就是字符集编码的由来。

下面介绍字符集发展和在 MySQL 中使用字符集:

字符集概述

简单的说,字符集就是一套文字符号及其编码、比较规则的合集。20世纪60年代 美国 ANSI(标准化组织)发布了ASCII 码,后来进一步变成国际标准 ISO-646。这个字符集采用七位编码,定义了包括了大小写字母、阿拉伯数字和符号、33个控制符号等。后来定制的各种字符集都是基于 ASCII 码定制的。

后来各大公司、各国政府、标准化组织先后发明了几百种字符集,比如 ISO-8859、GB2312、GBK、BIG5 等。这些字符集五花八门,导致各个国家的编码都不通用,后来出现了统一字符编码(Unicode)。

Unicode又经过一系列发展,出现了 UTF-8 的解决方案

汉字常见字符集

在计算机发展的不同阶段,我国参照当时的国际标准和实际需要,定制了一些汉字字符集编码标准:

  • GB2312-80: 于 1980 年发布,收录了 6763 个常用汉字和 682 个非汉字图形符号。
  • GB13000: 于 1993 年发布,除收录 GB2312-80 外,还收录了第 1、3、5、7 辅助集的全部汉字,共 27484 个,以及一些偏旁部首等。但 GB13000 推出后 并没有遭到业界支持,也就是一个形式上的标准。
  • GBK: 于 1995 年发布,在 GB2312 内码体系的基础上进行了扩充,收录了 GB13000.1-1993 的全部 20902 个 CJK 一统汉字,包括 GB2312 全部的 6763 个汉字。此外,还增补编码了 52 个汉字,13 个汉字结构符(表意文字描述符),和一些常用的部首与汉字部件。在 GBK 的内码系统中,并且 GB2312 的汉字所在码位不变,保证了 GBK 对 GB2312 的完全兼容。同时,GBK 内码与 GB13000.1 代码一一对应,为 GBK 兼容 13000.1 提供了解决版本。有趣的是,GBK 只是一个行业指导规范,并没有强制力吗,但是由于得到了 Microsoft Windows 95 的支持而大为流行。
  • GB18030: 于 2000 年发布,收录了 ISO/IEC 10646.1:2000 全部 27484 个 CJK 统一汉字,GB18030 是 GBK 的超集,也完全与 GB13000 向上兼容,定制 GB18030 也是为了解决 GBK 强制力不够的问题。

上面介绍集中汉字字符集,下面将常用字符集的特点归纳如表:

字符集 是否定长 编码方式 其他说明
ACSII 单字节 7 位编码 最早的奠基性字符集
ISO-8859-1/latin1 单字节 8 位编码 西欧字符集,经常被一些程序员用来转码
GB2312-80 双字节编码 早期标准,不推荐使用
GBK 双字节编码 虽然不是国标,但支持的系统不少
GB 18030 2 字节或 4 字节 开始有一些支持,但数据库支持的少见
UTF-32 4 字节编码 UCS-4 的原始编码,目前很少采用
UCS-2 2 字节编码 Windows 2000内部用 UCS-2
UTF-16 2 字节 或 4 字节编码 Java 和 Windows XP/NT 内部使用UTF-16
UTF-8 1 ~ 4 字节编码 互联网和 UNIX/Linux 广泛支持的 Unicode 字符集, MySQL Server也是用 UTF-8 ,包括两个子集 utf8 和 utf8mb4。

选择合适的字符集

对于数据库来说,字符集的选择更加重要。因为数据库中存储的大部分内容都是各种文字,字符集对数据库的存储、处理性能,以及日后系统的移植、推广都会受到影响。

MySQL5.7 目前支持几十种在字符集,包括USC-2,UTF-16,UTF-16LE、UTF-32、UTF-8 等 Unicode 字符集。面对众多字符集,我们该如何选择?

可以根据应用的需求,结合字符集的特点来做权衡。

  • 满足应用支持语言的需求,如果应用要处理各种各样的文字,或将发布到使用不同语言的国家或地区,就应该选用 Unicode 字符集。在 MySQL 中,最常用的字符集是UTF-8,其中 utf8mb3 和 utf8mb4 是 UTF-8 规则编码的两种字符集,后者是前者的超集。我们常说的 utf8 其实是 utf8mb3 的别名,3 表示这种字符集由 1 ~ 3 个字节组成。utf8mb4 表示这种字符集由 1~ 4个字节组成,如果需要支持 emoji 表情,通常需要选择 utf8mb4 的字符集来支持。随着互联网的发展,有越来越多的应用需要 utf8mb4 的字符集来支持。在最新的 MySQL8.0 中,默认字符集已经由 latin1 变为了 utf8mb4。
  • 如果应用中涉及到已有数据导入,就要充分考虑到数据库字符集对已有数据的兼容性。假如已有数据是 GBK 文字,如果选择 GB2312-80 为数据库字符集,就很有可能出现部分文字无法正常导入的情况。
  • 如果数据库只需要支持一般中文,数据量很大,性能要求也很高。那就应该选择双字节定长的中文字符集,比如 GBK。相对于 UTF-8 而言, GBK 的每个汉字只占用两个字节,而 UTF-8 的汉字编码需要三个字节,这样可以减少磁盘 I/O、数据库 cache 以及网络传输的时间,从而提供更好的性能。相反,如果应用主要处理英文字符,只有少部分的中文数据,那么 UTF-8 会更好,因为 GBK、UCS-2、UTF-16 的西文字编码都是两个字节,会造成很多不必要的开销。
  • 如果数据库需要做大量的字符运算,例如比较、排序等,那么选择定长字符集更好,因为定长字符集的处理速度要比变长字符集更快。
  • 如果所有的客户端都支持相同的字符集,则应该选择该字符集作为数据库字符集。这样可以避免因字符集转换而带来的性能开销和数据损失。

MySQL 支持的字符集简介

MySQL 服务器可以支持多种字符集,在同一台服务器、同一个数据库甚至同一个表的不同字段都可以使用不同的字符集,相比较其他数据库管理系统,在同一个数据库中只能使用相同的字符集,MySQL 明显存在更大的灵活性。

查看所有可用字符集的命令是 show character set

mysql> show character set;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |

或者查看 information_schema.character_sets ,可以显示所有字符集和该字符集默认排序的规则。

mysql> DESC information_schema.character_sets;
+----------------------+-------------+------+-----+---------+-------+
| Field                | Type        | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------+-------+
| CHARACTER_SET_NAME   | varchar(32) | NO   |     |         |       |
| DEFAULT_COLLATE_NAME | varchar(32) | NO   |     |         |       |
| DESCRIPTION          | varchar(60) | NO   |     |         |       |
| MAXLEN               | bigint(3)   | NO   |     | 0       |       |
+----------------------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

MySQL 的字符集包括字符集(CHARACTER)和排序规则(COLLATION)两个概念。其中字符集是用来定义 MySQL 存储字符串的方式,排序规则用来定义比较字符串的方式。字符集和排序规则是一对多的关系,MySQL 支持 30 多种字符集和 70 多种排序规则。

每个字符集最少对应一个排序规则。可以使用 SHOW COLLATION LIKE '***' 命令或者通过系统表 information_schema.COLLATIONS 来查看关键字符的排序规则。

mysql> SHOW COLLATION LIKE 'utf8%';
+--------------------------+---------+-----+---------+----------+---------+
| Collation                | Charset | Id  | Default | Compiled | Sortlen |
+--------------------------+---------+-----+---------+----------+---------+
| utf8_general_ci          | utf8    |  33 | Yes     | Yes      |       1 |
| utf8_bin                 | utf8    |  83 |         | Yes      |       1 |
| utf8_unicode_ci          | utf8    | 192 |         | Yes      |       8 |
| utf8_icelandic_ci        | utf8    | 193 |         | Yes      |       8 |
| utf8_latvian_ci          | utf8    | 194 |         | Yes      |       8 |
| utf8_romanian_ci         | utf8    | 195 |         | Yes      |       8 |
| utf8_slovenian_ci        | utf8    | 196 |         | Yes      |       8 |
...

mysql> DESC information_schema.COLLATIONS;
+--------------------+-------------+------+-----+---------+-------+
| Field              | Type        | Null | Key | Default | Extra |
+--------------------+-------------+------+-----+---------+-------+
| COLLATION_NAME     | varchar(32) | NO   |     |         |       |
| CHARACTER_SET_NAME | varchar(32) | NO   |     |         |       |
| ID                 | bigint(11)  | NO   |     | 0       |       |
| IS_DEFAULT         | varchar(3)  | NO   |     |         |       |
| IS_COMPILED        | varchar(3)  | NO   |     |         |       |
| SORTLEN            | bigint(3)   | NO   |     | 0       |       |
+--------------------+-------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

排序规则命名约定:它们以其相关的字符集名开始,通常包括一个语言名,并以 _ci(大小写不敏感)、_cs (大小写敏感)或 _bin (二元,即比较是基于字符编码的值而与 language 无关)结尾。

例如:

  • utf8_general_ci 是默认的排序规则,对大小写不敏感。
  • utf8_bin 按照编码的值进行比较,对大小写敏感。

在下面的例子中,如果指定 “A” 或 “a”按照 utf8_general_ci 去比较,则认为两个字符是相同的,如果按照 utf8_bin 去比较,则认为两个字符是不同的。我们事先需要确认应用的需求,是按照什么样的排序方式,是否需要区分大小写,以确定排序规则的选择。

mysql> SELECT IF('A' COLLATE utf8_general_ci = 'a' COLLATE utf8_general_ci,1,0AS 'IF';
+----+
| IF |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

mysql> SELECT IF('A' COLLATE utf8_bin = 'a' COLLATE utf8_bin,1,0AS 'IF';
+----+
| IF |
+----+
|  0 |
+----+
1 row in set (0.00 sec)

MySQL 字符集的设置

MySQL 的字符集和排序规则有 4 个级别的默认设置:服务器级、数据库级、表级和字段级。它们分别在不同的地方设置,作用也不相同。

服务器字符集和排序规则

服务器字符集和排序规则,可以在 MySQL 服务启动的时候确定。

  • 在 my.cnf 中设置:

    [mysqld]
    character-set-server=utf8
  • 在启动选项中指定:

    mysqld --character-set-server=utf8
  • 或者在编译的时候指定:

    shell> cmake . -DDEFAULT_CHARSET=utf8

如果没有使用特定的方法指定服务器字符集,那么 MySQL5.7 中默认使用 latin1 作为服务器字符集。上面三种方法都只是制定了字符集,并没有指定排序规则,这样意味着使用该字符集默认排序规则。如果要使用该字符集非默认的排序规则,则需要在指定字符集的同时指定排序规则。

注意: 在最新的 MySQL8.0 中,默认字符集已变为 utf8mb4

可以使用 show variables like 'character_set_server'; 命令查询当前服务器的字符集和排序规则:

mysql> show variables like 'character_set_server';
+----------------------+---------+
| Variable_name        | Value   |
+----------------------+---------+
| character_set_server | utf8mb4 |
+----------------------+---------+
1 row in set1 warning (0.00 sec)

mysql> show variables like 'collation_server';
+------------------+--------------------+
| Variable_name    | Value              |
+------------------+--------------------+
| collation_server | utf8mb4_unicode_ci |
+------------------+--------------------+
1 row in set1 warning (0.00 sec)

数据库字符集和排序规则

数据库的字符集和排序规则既可以在创建数据库的时候指定,也可以创建之后通过 alter database 命令修改。需要注意的是,如果数据库已经存有数据,因为修改字符集并不能将已有的数据按照新的字符集进行存放,所以不能脱过修改数据库的字符集直接修改数据的内容。

设置数据库字符集的规则如下:

  • 如果指定了字符集和排序规则,则使用指定的字符集和排序规则;
  • 如果指定了字符集但没有指定排序规则,则使用指定字符集的默认排序规则;
  • 如果指定了排序规则但未指定字符集,则字符集是使用与该排序规则关联的字符集;
  • 如果没有指定字符集和排序规则,则使用服务器字符集和排序规则作为数据库的字符集和排序规则;

推荐在创建数据库的时候明确指定字符集和排序规则,避免默认值受到影响。要显示当前数据库的字符集和排序规则。要显示当前数据库的字符集和排序规则,可以使用 show variables like 'character_set_database';  和 show variables like 'collation_database';命令查看:

mysql> show variables like 'character_set_database';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| character_set_database | utf8  |
+------------------------+-------+
1 row in set1 warning (0.00 sec)

mysql> show variables like 'collation_database';
+--------------------+-----------------+
| Variable_name      | Value           |
+--------------------+-----------------+
| collation_database | utf8_general_ci |
+--------------------+-----------------+
1 row in set1 warning (0.00 sec)

表字符集和排序规则

表的字符集和排序规则可以在创建表的时候指定,可以通过 alter table 命令进行修改,同样,如果表中已有记录,修改字符集对原有的记录并没有影响,不会按照新的字符集存放。表的字段仍然使用原来的字符集。

设置表的字符集和排序规则与数据库基本类似:

  • 如果指定了字符集和排序规则,则使用指定的字符集和排序规则;
  • 如果指定了字符集但没有指定排序规则,则使用指定字符集的默认排序规则;
  • 如果指定了排序规则但未指定字符集,则字符集是使用与该排序规则关联的字符集;
  • 如果没有指定字符集和排序规则,则使用数据库字符集和排序规则作为表的字符集和排序规则;

推荐在创建表的时候指定字符集和排序规则,以免受到默认值影响。要显示表的默认字符集和排序规则,可以使用 show create table 命令查看:

mysql> show create table salary G;
*************************** 1. row ***************************
       Table: salary
Create TableCREATE TABLE `salary` (
  `userid` int(11DEFAULT NULL,
  `salary` decimal(9,2DEFAULT NULL
ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)

列字符集排序规则

MySQL 可以定义列级别的字符集和排序规则,主要针对相同表的不同字段需要使用不同字符集的情况,应用一般不会碰到这种情况,只是 MySQL 提供给我们的一种灵活设置的手段。

列字符集和排序规则的定义可以在创建表的时候定义,或者在修改表的时候调整。如果在创建表的时候没有特别指定字符集和排序规则,则默认使用表的字符集和排序规则。

连接字符集和排序规则

上面的四种设置方式,确定的是数据保存的字符集和排序规则,对于实际的应用来说,还存在客户端和服务器之间交互的字符集和排序规则。

对于客户端和服务器的交互操作,MySQL 提供了 3 个不同的参数:character_set_clientcharacter_set_connectioncharacter_set_results 分别代表 客户端、连接、返回结果的字符集。通常这三个字符集是相同的,才可以确保正常的写入数据和读出,特别是对于中文字符,不同的写入字符集和返回字符集会导致写入的记录不能正常读出。

通常部分分别设置这三个参数,可以通过以下命令:

SET NAMES ***;

来设置连接的字符集和排序规则,这个命令可以同时修改这三个参数的值。使用这个方法修改字符集和排序规则,仅当前连接有效,下次连接时依然需要执行这个命令。

还可以直接从 my.cnf 中设置:

[mysql]
default-character-set=utf8

设置后,所有连接默认使用utf8,另外字符串常量的字符集也是由 character_set_connection 参数来指定的。

可以通过 [charset_name]'string'[COLLATE collation_name] 强制设置字符串的字符集和排序规则:

select _utf8 '字符集';
select _latin1 '字符集';

通常情况下不需要用户强制指定字符串的字符集。

字符集修改步骤

如果在应用开始阶段没有正确的设置字符集,在运行一段时间之后才发现存在不能满足需求需要调整,又不想丢弃这段时间的数据,那就需要进行对字符集的修改。字符集的修改不能通过 alter database character set ***alter table tablename character set *** 两个命令进行修改,这两个命令没有更新已有记录的字符集,而只是对新创建的表或记录生效。已有记录的字符集调整,需要先将数据导出,经过适当调整后重新导入才可完成。

注意: 选择目标字符集的时候,要注意最好选择的是原字符集的超集,或者确定比原字符集的字库更大,否则如果目标字符集的字库更小,那么目标字符集中不支持的字符导入后会变成乱码,丢失一部分数据。

例如:GBK 的字符集字库就大于 GB2312 字符集,那么 GBK 字符集的数据如果导入 GB2321 数据库中,就会丢失 GB2312 中不支持的那部分汉字的数据。


原文始发于微信公众号(两双筷子):MySQL字符集

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/78486.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!