MySQL 字符集和校对——《高性能MySQL》

读《高性能MySQL》第三版,笔记。

1、字符集和校对

字符集:是指一种从二进制编码到某类字符符号的映射,可以参考如何使用一个字节来表示英文字母。

校对:是指一组用于某个字符集的排序规则。

MySQL 4.1 和之后的版本中,每一类编码字符都有对应的字符集和校对规则。

1.1、MySQL 如何使用字符集

每种字符集都可能有多种校对规则,并且都有一个默认的校对规则。

每个校对规则都是针对某个特定的字符集的,和其他的字符集没有关系。

MySQL 的设置可以分为两类:创建对象时的默认值、在服务器和客户端通信时的设置。

创建对象时的默认设置

MySQL 服务器有默认的字符集和校对规则,每个数据库也有自己的默认值,每个表也有自己的默认值。

这是一个逐层继承的默认设置,最终最底层的默认设置将影响你创建的对象。

这些默认值,至上而下地告诉 MySQL 应该使用什么字符集来存储某个列。

在这个 “ 阶梯 ” 的每一层,你都可以指定一个特定的字符集或者让服务器使用它的默认值:

  • 创建数据库的时候,将根据服务器上的 character_set_server 设置类设定该数据库的默认字符集。
  • 创建表的时候,将根据数据库的字符集设置指定这个表的字符集设置。
  • 创建列的时候,将根据表的设置指定列的字符集设置。

需要记住的是,真正存放数据的是列,所以更高 “ 阶梯 ” 的设置只是指定默认值。

一个表的默认字符集设置无法影响存储在这个表中某个列的值。

只有当创建而没有为列指定字符集的时候,如果没有指定字符集,表的默认字符集才有作用。

服务器和客户端通信时的设置

当服务器和客户端通信的时候,它们可能使用不同的字符集。

这时,服务器端将进行必要的翻译转换工作:

  • 服务器端总是假设客户端时按照 character_set_client 设置的字符来传输数据和 SQL 语句的。
  • 当服务器收到客户端的 SQL 语句时,它先将器转换成字符集 character_set_connection 。它还使用这个设置来决定如何将数据转换成字符串。
  • 当服务器端返回数据或者错误信息给客户端时,它会将其转换成 character_set_result

根据需要,可以使用 SET NAMES 或者 SET CHARACTER SET 语句来改变上面的设置。不过在服务器上使用这个命令只能改变服务器端的设置。客户端程序和客户端的 API 也需要使用正确的字符集才能避免在通信时出现问题。

MySQL 如何比较两个字符串的大小

如果比较的两个字符串的字符集不同,MySQL 会先将其转成同一个字符集再进行比较。

如果两个字符集不兼容的话,则会抛出错误。MySQL 5.0 和更新的版本经常会做这样的隐式转换,所以这类错误通常是在 MySQL 4.1 中比较常见。

MySQL 还会为每个字符串设置一个 “ 可转换性 ”(coercibility() 函数的返回值)。这个设置决定了值的字符集的优先级,因而会影响 MySQL 做字符集隐式转换后的值。

还可以使用前缀和 COLLATE 子句来指定字符串的字符集或者校对字符集。

mysql> SELECT _utf8 'hello world' COLLATE utf8_bin;
+--------------------------------------+
| _utf8 'hello world' COLLATE utf8_bin |
+--------------------------------------+
| hello world                          |
+--------------------------------------+
1 row in set (0.01 sec)

1.2、选择字符集和校对规则

MySQL 4.1 和之后的版本支持很多的字符集和校对规则,包括支持使用 Unicode 编码的多字节 UTF-8 。

可以使用命令 SHOW CHARACTER SETSHOW COLLATION 来查看 MySQL 支持的字符集和校对规则。

正确的方法是,最好先为服务器(或者数据库)选择一个合理的字符集。然后根据不同的实际情况,让某些列选择合适的字符集。

对于校对规则通常需要考虑的一个问题是,是否以大小写敏感的方式比较字符串,或者是以字符串编码的二进制来比较大小。

前缀说明
_cs大小敏感
_ci大小不敏感
_bin二进制比较

大小写敏感和二进制校对规则的不同之处在于,二进制校对规则直接使用字符的字节进行比较,而大小写敏感的校对规则在多字节字符集时,如德语,有更复杂的比较规则。

在显式设置字符集的时候,并不是必须同时指定字符集和校对规则的名字。

如果缺失了其中一个或者两个,MySQL 会使用可能的默认值来进行填充。

MySQL 如何选择字符集和校对规则:

用户设置返回结果的字符集返回结果的校对规则
同时设置字符集和校对规则与用户设置相同与用户设置相同
仅设置字符集与用户设置相同与字符集的默认校对规则相同
仅设置校对规则与校对规则对象的字符集相同与用户设置相同
都未设置使用默认值使用默认值

查询表的字符集和校对规则:

mysql> show full columns from city;
+-------------+----------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
| Field       | Type     | Collation         | Null | Key | Default | Extra          | Privileges                      | Comment |
+-------------+----------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
| ID          | int(11)  | NULL              | NO   | PRI | NULL    | auto_increment | select,insert,update,references |         |
| Name        | char(35) | latin1_swedish_ci | NO   |     |         |                | select,insert,update,references |         |
| CountryCode | char(3)  | latin1_swedish_ci | NO   | MUL |         |                | select,insert,update,references |         |
| District    | char(20) | latin1_swedish_ci | NO   |     |         |                | select,insert,update,references |         |
| Population  | int(11)  | NULL              | NO   |     | 0       |                | select,insert,update,references |         |
+-------------+----------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
5 rows in set (0.00 sec)

1.3、字符集和校对规则如何影响查询

某些字符集和校对规则可能会需要更多的 CPU 操作,可能会消耗更多的内存和存储空间,甚至还会影响索引的正常使用。

所以在选择字符集的时候,也有一些需要注意的地方。

不同的字符集和校对规则之间的转换可能会带来额外的系统开销。

只有排序查询要求的字符集和服务器数据的字符集相同的时候,才能使用索引进行排序。

为了能够适应各种字符集,包括客户端字符集、在查询中显式指定的字符集,MySQL 会在需要的时候进行字符集转换。如果你不确定 MySQL 内部是否做了这种转换,可以在 EXPLAIN EXTENDED(也可以直接 EXPLAIN)后使用 SHOW WARNINGS 来查看 MySQL 是如何处理的。

UTF-8 是一种多字节编码,它存储一个字符会使用变长的字节数(一到三个字节)。在 MySQL 内存,通常使用一个定长的空间来存储字符串,再进行相关操作,这样做的目的是希望总是保证缓存中有足够的空间来存储字符串。

另一个 “ 惊喜 ” 可能是关于索引限制方面的。如果要索引一个 UTF-8 字符集的列, MySQL 会假设每一个字符都是三个字节,所以最长索引前缀的限制一下缩短到原来的三分之一了。

也有人建议,直接使用 UTF-8 字符集,“ 整个世界都清净了 ”。不过从性能的角度来看这不是一个好注意。根据存储的数据,很多应用无须使用 UTF-8 字符集,如果坚持使用 UTF-8 ,只会消耗更多的磁盘空间。

在考虑使用什么字符集的时候,需要根据存储的具体内存来决定。

有时候根本不需要使用任何的字符集。通常只有在做大小写无关的比较、排序、字符串操作的时候才需要使用字符集。如果你的数据库不关心字符集,那么可以直接将所有的东西存储到二进制列中。这会导致很多难以排查的错误,如果可能,不建议使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值