MySQL 字符集与排序规则(一)

最近碰到好几次MySQL乱码的问题,所以这次想看看MySQL文档上到底是怎么说的。

MySQL5.6的文档还专门有一章来介绍字符集、排序规则和Unicode。5.7就没了,放在了Globalization里面。

熟悉英文的朋友直接移步官方文档。

字符集支持

MySQL支持字符集,包括使用各种字符集来存储数据和根据不同的排序规则来进行比较。你可在服务,数据库,数据表,行几个级别上指定字符集。MySQL支持在MyISAM,MEMORY,InnoDB几个引擎上使用字符集。

本章讨论下面几个主题:

  • 什么是字符集和排序规则?
  • 用于字符集分配的多级别默认系统
  • 指定字符集和排序规则的语法
  • 受影响的函数和操作
  • Unicode支持
  • 可用的字符集和排序规则

字符集不仅影响数据存储,而且也影响客户端程序和MySQL服务的通信。如果你希望客户端程序使用非默认的字符集和MySQL服务通信,那么你需要指定是哪一个。例如,使用utf8 Unicode字符集,连接到服务器后需要执行下面的语句:

1
SET NAMES 'utf8';

普遍意义上的字符集和排序规则

字符集是一组符号和编码。排序规则是比较字符集中字符的一组规则。让我们用一个虚构的字符集例子来区分清他们。

假设我们有一个带有四个字母的字母:A,B,a,b。我们给每个字母一个编号:A = 0,B = 1,a = 2,b = 3。字母A就是符号,数字0就是A的编码,四个字母和他们的编码的组合就是字符集。

假设我们想比较两个字符串,A和B。最简单的方式就是看他们的编码:0代表A,1代表B。因为0小于1,所以我们说A小于B。我们刚刚做的就是为字符集应用排序规则。排序规则就是一组规则(在这个例子中仅有一个规则):“比较编码”。我们称所有可能排序规则中这种最简单的为二进制排序规则。

但是,如果我们想说大写和小写字母是相等的呢?然后我们至少会有两个规则:1. 将小写字母a,b视为和A,B相等;2. 比较编码。我们称这种为大小写不敏感的排序规则,它要比二进制排序规则复杂一点。

真是情况下,大多数字符集有很多字符:有时候不单单是A和B,而是整个字母,多字符或者东方的书写系统,有数千个字符,还有许多特殊字符和标点符号。同样,大多数的排序规则也有很多规则,不仅区分字母,还区分口音(“重音”是德语中字符的附加标记Ö),还有多字符映射(例如两个德语排序规则中的一个规定Ö = OE)。

MySQL能为我们做这些事:

  • 使用多种字符集存储字符串
  • 使用多种排序规则比较字符
  • 在同一服务器,同一数据库,甚至同一个数据表中混用不同的字符集或排序规则
  • 在任何级别启用字符集和排序规则

为了更有效的使用这些特性,你必须知道哪些字符集和排序规则可用,如果改变默认的设置,知道他们是怎么影响了字符串操作和函数。

MySQL中的字符集和排序规则

MySQL服务支持多种字符集,使用INFORMATION_SCHEMA CHARACTER_SETS或者SHOW CHARACTER SET语句可以查看可用的字符集,默认SHOW CHARACTER SET语句默认显示所有的字符集。这两个语句都可以使用LIKEWHERE来显示匹配的字符集。例如:

1
2
3
4
5
6
7
8
mysql> SHOW CHARACTER SET LIKE 'utf%';

+---------+---------------+-------------------+--------+
| Charset | Description | Default collation | Maxlen |
+---------+---------------+-------------------+--------+
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
+---------+---------------+-------------------+--------+
1 row in set (0.00 sec)

上面每个给出的字符集至少有一个排序规则,大多数字符集都有多个排序规则。可以通过INFORMATION_SCHEMA COLLATIONSSHOW COLLATION显示排序规则。

默认情况下,SHOW COLLATION语句会列出所有可用的排序规则。也可以对他应用LIKEWHERE语句。例如显示默认字符集latin1(cp1252 西欧)的排序规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SHOW COLLATION WHERE Charset = 'latin1';

+-------------------+---------+----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1 | 5 | | Yes | 1 |
| latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 |
| latin1_danish_ci | latin1 | 15 | | Yes | 1 |
| latin1_german2_ci | latin1 | 31 | | Yes | 2 |
| latin1_bin | latin1 | 47 | | Yes | 1 |
| latin1_general_ci | latin1 | 48 | | Yes | 1 |
| latin1_general_cs | latin1 | 49 | | Yes | 1 |
| latin1_spanish_ci | latin1 | 94 | | Yes | 1 |
+-------------------+---------+----+---------+----------+---------+
8 rows in set (0.00 sec)

latin1排序规则有下面的意义:

排序规则 含义
latin1_bin 根据latin_1编码的二进制
latin1_danish_ci 丹麦/挪威
latin1_general_ci 多语言(西欧)
latin1_general_cs 多语言(ISO 西欧),大小写敏感
latin1_german1_ci 德国DIN-1(字典顺序)
latin1_german2_ci 德国DIN-2(电话簿顺讯)
latin1_spanish_ci 现代西班牙语
latin1_swedish_ci 瑞典/芬兰

排序规则的一般的特点:

  • 两种不同的字符集不会有相同的排序规则。
  • 每个字符集有默认的排序规则。例如,latin1的默认排序规则是latin1_swedish_ci,utf8的是utf8_general_ci。默认排序规则从SHOW CHARACTER SETSHOW COLLATION里面都能看出来,就不赘述了。
  • 排序规则的名字以跟他们关联的字符集的名字开头,之后跟一个或多个后缀表明其特征。

当字符集有多个排序规则的时候,可能不清楚哪种规则更适合给定的应用。为了避免选择一个不合适的排序规则,应该对一些有代表性的数据进行比较以确保给定的排序规则和预期的一样。