MySQL8 中文参考(四十三)
12.5 配置应用程序字符集和校对规则
原文:
dev.mysql.com/doc/refman/8.0/en/charset-applications.html
对于使用默认 MySQL 字符集和校对规则(utf8mb4、utf8mb4_0900_ai_ci)存储数据的应用程序,不需要特殊配置。如果应用程序需要使用不同的字符集或校对规则进行数据存储,可以通过多种方式配置字符集信息:
-
为每个数据库指定字符设置。例如,使用一个数据库的应用程序可能使用
utf8mb4的默认设置,而使用另一个数据库的应用程序可能使用sjis。 -
在服务器启动时指定字符设置。这将导致服务器对所有未做其他安排的应用程序使用给定设置。
-
如果从源代码构建 MySQL,请在配置时指定字符设置。这将导致服务器将给定设置用作所有应用程序的默认设置,而无需在服务器启动时指定它们。
当不同应用程序需要不同的字符设置时,每个数据库的技术提供了很大的灵活性。如果大多数或所有应用程序使用相同的字符集,则在服务器启动时或配置时指定字符设置可能是最方便的。
对于每个数据库或服务器启动技术,这些设置控制数据存储的字符集。应用程序还必须告诉服务器在客户端/服务器通信中使用哪种字符集,如下面的说明所述。
这里展示的示例假定在特定情境下使用latin1字符集和latin1_swedish_ci校对规则,作为utf8mb4和utf8mb4_0900_ai_ci默认设置的替代方案。
-
为每个数据库指定字符设置。 要创建一个数据库,使其表使用给定的默认字符集和校对规则进行数据存储,请使用类似于以下的
CREATE DATABASE语句:CREATE DATABASE mydb CHARACTER SET latin1 COLLATE latin1_swedish_ci;数据库中创建的表默认使用
latin1和latin1_swedish_ci作为任何字符列的字符集。使用数据库的应用程序在每次连接时也应配置与服务器的连接。这可以通过连接后执行
SET NAMES 'latin1'语句来完成。该语句可用于任何连接方法(mysql客户端、PHP 脚本等)。在某些情况下,可能可以通过其他方式配置连接以使用所需的字符集。例如,要使用mysql连接,可以指定
--default-character-set=latin1命令行选项,以实现与SET NAMES 'latin1'相同的效果。有关配置客户端连接的更多信息,请参见第 12.4 节,“连接字符集和校对规则”。
注意
如果您使用
ALTER DATABASE更改数据库默认字符集或校对规则,则必须删除并重新创建数据库中使用这些默认设置的现有存储过程,以便它们使用新的默认设置。(在存储过程中,如果未明确指定字符集或校对规则,则具有字符数据类型的变量将使用数据库默认设置。请参见第 15.1.17 节,“CREATE PROCEDURE 和 CREATE FUNCTION 语句”。) -
在服务器启动时指定字符设置。 要在服务器启动时选择字符集和校对规则,请使用
--character-set-server和--collation-server选项。例如,要在选项文件中指定这些选项,请包含以下行:[mysqld] character-set-server=latin1 collation-server=latin1_swedish_ci这些设置适用于整个服务器,并作为任何应用程序创建的数据库以及在这些数据库中创建的表的默认设置。
应用程序仍然需要在连接后使用
SET NAMES或等效方法配置其连接,如前所述。您可能会尝试使用--init_connect="SET NAMES 'latin1'"选项启动服务器,以使SET NAMES自动为每个连接的客户端执行。但是,这可能会产生不一致的结果,因为具有CONNECTION_ADMIN权限(或已弃用的SUPER权限)的用户不会执行init_connect值。 -
在 MySQL 配置时间指定字符设置。 如果您从源代码配置和构建 MySQL,可以使用
DEFAULT_CHARSET和DEFAULT_COLLATIONCMake选项来选择字符集和校对规则:cmake . -DDEFAULT_CHARSET=latin1 \ -DDEFAULT_COLLATION=latin1_swedish_ci结果服务器使用
latin1和latin1_swedish_ci作为数据库和表以及客户端连接的默认设置。在服务器启动时不需要使用--character-set-server和--collation-server来指定这些默认设置。应用程序也无需在连接到服务器后使用SET NAMES或等效方法配置其连接。
无论您如何为应用程序配置 MySQL 字符集,您还必须考虑这些应用程序执行的环境。例如,如果您打算使用从编辑器中创建的文件中的 UTF-8 文本发送语句,您应该将文件的编辑环境设置为 UTF-8,以便文件编码正确,并且操作系统正确处理它。如果您在终端窗口中使用mysql客户端,窗口必须配置为使用 UTF-8,否则字符可能无法正确显示。对于在 Web 环境中执行的脚本,脚本必须正确处理字符编码以便与 MySQL 服务器交互,并且必须生成正确指示编码的页面,以便浏览器知道如何显示页面内容。例如,您可以在<head>元素中包含此<meta>标签:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
12.6 错误消息字符集
本节描述了 MySQL 服务器如何使用字符集构造错误消息。有关错误消息的语言(而不是字符集)的信息,请参见第 12.12 节,“设置错误消息语言”。有关配置错误日志的一般信息,请参见第 7.4.2 节,“错误日志”。
-
错误消息构造的字符集
-
错误消息处置的字符集
错误消息构造的字符集
服务器构造错误消息如下:
-
消息模板使用 UTF-8(
utf8mb3)。 -
消息模板中的参数将被替换为适用于特定错误发生的值:
-
诸如表或列名的标识符在内部使用 UTF-8,因此它们被直接复制。
-
字符(非二进制)字符串值从其字符集转换为 UTF-8。
-
二进制字符串值在范围
0x20至0x7E的字节中被直接复制,对于范围之外的字节则使用\x十六进制编码。例如,如果尝试将0x41CF9F插入到VARBINARY唯一列中导致重复键错误,则生成的错误消息将使用 UTF-8,并对一些字节进行十六进制编码:Duplicate entry 'A\xCF\x9F' for key 1
-
错误消息处置的字符集
一旦构造完成,错误消息可以由服务器写入错误日志或发送给客户端:
-
如果服务器将错误消息写入错误日志,则会按照构造的 UTF-8 格式写入,而不会转换为其他字符集。
-
如果服务器将错误消息发送给客户端程序,则服务器将其从 UTF-8 转换为由
character_set_results系统变量指定的字符集。如果character_set_results的值为NULL或binary,则不会进行转换。如果变量值为utf8mb3或utf8mb4,也不会进行转换,因为这些字符集包含了消息构造中使用的所有 UTF-8 字符。如果字符无法表示为
character_set_results中的字符集,则在转换过程中可能会发生一些编码。编码使用 Unicode 代码点值:-
基本多语言平面(BMP)范围内的字符(
0x0000至0xFFFF)使用\*nnnn*表示。 -
超出 BMP 范围(
0x10000至0x10FFFF)的字符使用\+*nnnnnn*表示。
客户端可以设置
character_set_results来控制他们接收错误消息的字符集。该变量可以直接设置,也可以通过诸如SET NAMES等方式间接设置。有关character_set_results的更多信息,请参见第 12.4 节,“连接字符集和校对”。 -
12.7 列字符集转换
要将二进制或非二进制字符串列转换为使用特定字符集,请使用ALTER TABLE。要成功转换,必须满足以下条件之一:
-
如果列具有二进制数据类型(
BINARY,VARBINARY,BLOB),则它包含的所有值必须使用单个字符集进行编码(您正在将列转换为的字符集)。如果使用二进制列存储多个字符集的信息,MySQL 无法知道哪些值使用哪个字符集,并且无法正确转换数据。 -
如果列具有非二进制数据类型(
CHAR,VARCHAR,TEXT),其内容应该以列字符集编码,而不是其他字符集。如果内容以不同的字符集编码,您可以先将列转换为使用二进制数据类型,然后再转换为具有所需字符集的非二进制列。
假设表t有一个名为col1的二进制列,定义为VARBINARY(50)。假设列中的信息使用单个字符集进行编码,您可以将其转换为具有该字符集的非二进制列。例如,如果col1包含代表greek字符集中字符的二进制数据,则可以按如下方式进行转换:
ALTER TABLE t MODIFY col1 VARCHAR(50) CHARACTER SET greek;
如果您的原始列类型为BINARY(50),您可以将其转换为CHAR(50),但结果值将在末尾填充0x00字节,这可能是不希望的。要删除这些字节,请使用TRIM()函数:
UPDATE t SET col1 = TRIM(TRAILING 0x00 FROM col1);
假设表t有一个名为col1的非二进制列,定义为CHAR(50) CHARACTER SET latin1,但您希望将其转换为使用utf8mb4,以便存储来自许多语言的值。以下语句可以实现这一目标:
ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET utf8mb4;
如果列包含不在两个字符集中的字符,则转换可能会有损失。
如果您有 MySQL 4.1 之前的旧表,其中一个非二进制列包含实际上是使用与服务器默认字符集不同的字符集编码的值,则会出现特殊情况。例如,一个应用程序可能已经在列中存储了sjis值,尽管 MySQL 的默认字符集不同。可以将列转换为使用正确的字符集,但需要额外的步骤。假设服务器的默认字符集是latin1,col1被定义为CHAR(50),但其内容是sjis值。第一步是将列转换为二进制数据类型,这将删除现有的字符集信息而不执行任何字符转换:
ALTER TABLE t MODIFY col1 BLOB;
下一步是将列转换为具有正确字符集的非二进制数据类型:
ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET sjis;
在将 MySQL 升级到 4.1 或更高版本后,此过程要求表在使用INSERT或UPDATE等语句修改之前未被修改。在这种情况下,MySQL 将使用latin1存储新值在列中,并且该列将包含sjis和latin1值的混合,无法正确转换。
如果在创建列时指定了属性,那么在使用ALTER TABLE修改表时也应该指定这些属性。例如,如果您指定了NOT NULL和一个明确的DEFAULT值,那么在ALTER TABLE语句中也应该提供它们。否则,生成的列定义将不包括这些属性。
要转换表中的所有字符列,ALTER TABLE ... CONVERT TO CHARACTER SET *charset*语句可能会有用。请参阅第 15.1.9 节,“ALTER TABLE Statement”。
12.8 排序规则问题
12.8.1 在 SQL 语句中使用 COLLATE
12.8.2 COLLATE 子句的优先级
12.8.3 字符集和排序规则兼容性
12.8.4 表达式中的排序规则强制性
12.8.5 二进制排序规则与 _bin 排序规则的比较
12.8.6 排序规则效果示例
12.8.7 在 INFORMATION_SCHEMA 搜索中使用排序规则
以下各节讨论了字符集排序规则的各个方面。
12.8.1 在 SQL 语句中使用 COLLATE
使用COLLATE子句,您可以覆盖比较的默认排序规则。COLLATE可以在 SQL 语句的各个部分中使用。以下是一些示例:
-
在
ORDER BY中:SELECT k FROM t1 ORDER BY k COLLATE latin1_german2_ci; -
在
AS中:SELECT k COLLATE latin1_german2_ci AS k1 FROM t1 ORDER BY k1; -
在
GROUP BY中:SELECT k FROM t1 GROUP BY k COLLATE latin1_german2_ci; -
在聚合函数中:
SELECT MAX(k COLLATE latin1_german2_ci) FROM t1; -
在
DISTINCT中:SELECT DISTINCT k COLLATE latin1_german2_ci FROM t1; -
在
WHERE中:SELECT * FROM t1 WHERE _latin1 'Müller' COLLATE latin1_german2_ci = k;SELECT * FROM t1 WHERE k LIKE _latin1 'Müller' COLLATE latin1_german2_ci; -
在
HAVING中:SELECT k FROM t1 GROUP BY k HAVING k = _latin1 'Müller' COLLATE latin1_german2_ci;
12.8.2 COLLATE 子句优先级
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collate-precedence.html
COLLATE子句具有很高的优先级(高于||),因此以下两个表达式是等价的:
x || y COLLATE z
x || (y COLLATE z)
12.8.3 字符集和排序兼容性
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-compatibility.html
每个字符集都有一个或多个排序规则,但每个排序规则只与一个字符集相关联。因此,以下语句会导致错误消息,因为latin2_bin排序规则与latin1字符集不兼容:
mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid
for CHARACTER SET 'latin1'
12.8.4 表达式中的排序强制性
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-coercibility.html
在绝大多数语句中,MySQL 使用哪个排序来解决比较操作是显而易见的。例如,在以下情况下,应该清楚 MySQL 使用的排序是列x的排序:
SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;
然而,对于多个操作数,可能存在歧义。例如,此语句执行列x和字符串常量'Y'之间的比较:
SELECT x FROM T WHERE x = 'Y';
如果x和'Y'具有相同的排序,则对于比较要使用的排序就没有歧义。但是,如果它们具有不同的排序,比较应该使用x的排序还是'Y'的排序?x和'Y'都有排序,那么哪个排序优先?
混合排序也可能发生在除比较之外的上下文中。例如,多参数连接操作CONCAT(x,'Y')将其参数组合成一个字符串。结果应该具有什么排序?
为了解决这类问题,MySQL 检查一个项目的排序是否可以强制转换为另一个项目的排序。MySQL 分配强制性值如下:
-
明确的
COLLATE子句具有强制性为 0(根本不可强制转换)。 -
具有不同排序的两个字符串的连接具有强制性为 1。
-
列或存储过程参数或局部变量的排序具有强制性为 2。
-
“系统常量”(由函数返回的字符串,如
USER()或VERSION())具有强制性为 3。 -
文本常量的排序具有强制性为 4。
-
数值或时间值的排序具有强制性为 5。
-
NULL或从NULL派生的表达式具有强制性为 6。
MySQL 使用以下规则的强制性值来解决歧义:
-
使用具有最低强制性值的排序。
-
如果两侧具有相同的强制性,则:
-
如果两侧都是 Unicode,或两侧都不是 Unicode,则会出现错误。
-
如果一侧具有 Unicode 字符集,另一侧具有非 Unicode 字符集,则具有 Unicode 字符集的一侧获胜,并且自动进行字符集转换应用于非 Unicode 侧。例如,以下语句不会返回错误:
SELECT CONCAT(utf8mb4_column, latin1_column) FROM t1;它返回一个具有字符集
utf8mb4和与utf8mb4_column相同排序的结果。在连接之前,latin1_column的值会自动转换为utf8mb4。 -
对于使用相同字符集但混合了
_bin排序和_ci或_cs排序的操作,将使用_bin排序。这类似于将混合非二进制和二进制字符串的操作将操作数评估为二进制字符串,只是应用于排序而不是数据类型。
-
尽管自动转换不在 SQL 标准中,但标准确实指出每个字符集(在支持的字符方面)都是 Unicode 的“子集”。因为“适用于超集的原则也适用于子集”是一个众所周知的原则,我们认为 Unicode 的排序可以用于与非 Unicode 字符串的比较。更一般地说,MySQL 使用字符集库的概念,有时可以用于确定字符集之间的子集关系,并使操作中的操作数转换为否则会产生错误的操作。参见 Section 12.2.1, “Character Set Repertoire”。
以下表格说明了前述规则的一些应用。
| 比较 | 使用的排序 |
|---|---|
column1 = 'A' | 使用column1的排序 |
column1 = 'A' COLLATE x | 使用'A' COLLATE x的排序 |
column1 COLLATE x = 'A' COLLATE y | 错误 |
要确定字符串表达式的可强制性,使用COERCIBILITY()函数(参见 Section 14.15, “Information Functions”):
mysql> SELECT COERCIBILITY(_utf8mb4'A' COLLATE utf8mb4_bin);
-> 0
mysql> SELECT COERCIBILITY(VERSION());
-> 3
mysql> SELECT COERCIBILITY('A');
-> 4
mysql> SELECT COERCIBILITY(1000);
-> 5
mysql> SELECT COERCIBILITY(NULL);
-> 6
对于将数值或时间值隐式转换为字符串,例如在表达式CONCAT(1, 'abc')中对参数1的情况,结果是一个由character_set_connection和collation_connection系统变量确定字符集和排序的字符(非二进制)字符串。参见 Section 14.3, “Type Conversion in Expression Evaluation”。
12.8.5 二进制排序规则与 _bin 排序规则的比较
原文:
dev.mysql.com/doc/refman/8.0/en/charset-binary-collations.html
本节描述了二进制字符串的binary排序规则与非二进制字符串的_bin排序规则的比较。
使用BINARY、VARBINARY和BLOB数据类型存储的二进制字符串具有名为binary的字符集和排序规则。二进制字符串是字节序列,这些字节的数值确定了比较和排序顺序。参见第 12.10.8 节,“二进制字符集”。
使用CHAR、VARCHAR和TEXT数据类型存储的非二进制字符串具有除binary之外的字符集和排序规则。给定的非二进制字符集可以有多个排序规则,每个规则定义了集合中字符的特定比较和排序顺序。对于大多数字符集,其中一个是二进制排序规则,在排序规则名称中以_bin后缀表示。例如,latin1和big5的二进制排序规则分别命名为latin1_bin和big5_bin。utf8mb4是一个例外,它有两个二进制排序规则,分别是utf8mb4_bin和utf8mb4_0900_bin;参见第 12.10.1 节,“Unicode 字符集”。
binary排序规则在几个方面与_bin排序规则不同,将在以下部分讨论:
-
比较和排序的单位
-
字符集转换
-
大小写转换
-
比较中的尾随空格处理
-
插入和检索的尾随空格处理
比较和排序的单位
二进制字符串是字节序列。对于binary校对规则,比较和排序基于数字字节值。非二进制字符串是字符序列,可能是多字节的。非二进制字符串的校对规则定义了用于比较和排序的字符值排序。对于_bin校对规则,此排序基于数字字符代码值,类似于二进制字符串的排序,只是字符代码值可能是多字节的。
字符集转换
非二进制字符串具有一个字符集,并且在许多情况下会自动转换为另一个字符集,即使字符串具有_bin校对规则:
-
将列值分配给具有不同字符集的另一列时:
UPDATE t1 SET utf8mb4_bin_column=latin1_column; INSERT INTO t1 (latin1_column) SELECT utf8mb4_bin_column FROM t2; -
当使用字符串字面值为
INSERT或UPDATE分配列值时:SET NAMES latin1; INSERT INTO t1 (utf8mb4_bin_column) VALUES ('string-in-latin1'); -
从服务器发送结果到客户端时:
SET NAMES latin1; SELECT utf8mb4_bin_column FROM t2;
对于二进制字符串列,不会发生转换。对于类似的情况,字符串值会逐字节复制。
大小写转换
非二进制字符集的校对规则提供了关于字符大小写的信息,因此非二进制字符串中的字符可以从一个大小写转换为另一个大小写,即使是对于忽略大小写进行排序的_bin校对规则:
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT LOWER('aA'), UPPER('zZ');
+-------------+-------------+
| LOWER('aA') | UPPER('zZ') |
+-------------+-------------+
| aa | ZZ |
+-------------+-------------+
字节中的大小写概念不适用于二进制字符串。要执行大小写转换,必须首先使用适合存储在字符串中的数据的字符集将字符串转换为非二进制字符串:
mysql> SET NAMES binary;
mysql> SELECT LOWER('aA'), LOWER(CONVERT('aA' USING utf8mb4));
+-------------+------------------------------------+
| LOWER('aA') | LOWER(CONVERT('aA' USING utf8mb4)) |
+-------------+------------------------------------+
| aA | aa |
+-------------+------------------------------------+
比较中处理末尾空格
MySQL 校对规则具有一个PAD SPACE或NO PAD的填充属性:
-
大多数 MySQL 校对规则具有
PAD SPACE的填充属性。 -
基于 UCA 9.0.0 及更高版本的 Unicode 校对规则具有
NO PAD的填充属性;参见第 12.10.1 节,“Unicode 字符集”。
对于非二进制字符串(CHAR,VARCHAR和TEXT值),字符串校对填充属性决定了在比较末尾空格时的处理方式:
-
对于
PAD SPACE校对规则,比较中末尾空格不重要;字符串比较时不考虑末尾空格。 -
NO PAD校对规则将末尾空格视为比较中的重要字符,就像任何其他字符一样。
这些不同的行为可以使用两个utf8mb4二进制校对规则来演示,其中一个是PAD SPACE,另一个是NO PAD。示例还展示了如何使用INFORMATION_SCHEMA COLLATIONS表来确定校对规则的填充属性。
mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE COLLATION_NAME LIKE 'utf8mb4%bin';
+------------------+---------------+
| COLLATION_NAME | PAD_ATTRIBUTE |
+------------------+---------------+
| utf8mb4_bin | PAD SPACE |
| utf8mb4_0900_bin | NO PAD |
+------------------+---------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 1 |
+------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_0900_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 0 |
+------------+
注意
在此上下文中的“比较”不包括LIKE模式匹配运算符,对于这些运算符,无论校对规则如何,末尾空格都是重要的。
对于二进制字符串(BINARY,VARBINARY和BLOB值),在比较中所有字节都是重要的,包括尾随空格:
mysql> SET NAMES binary;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
| 0 |
+------------+
插入和检索的尾随空格处理
CHAR(*N*)列存储长度为*N个字符的非二进制字符串。对于插入操作,长度小于N*个字符的值将用空格扩展。对于检索,尾随空格将被移除。
BINARY(*N*)列存储长度为*N字节的二进制字符串。对于插入操作,长度小于N*字节的值将用0x00字节扩展。对于检索,不会删除任何内容;始终返回声明长度的值。
mysql> CREATE TABLE t1 (
a CHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
b BINARY(10)
);
mysql> INSERT INTO t1 VALUES ('x','x');
mysql> INSERT INTO t1 VALUES ('x ','x ');
mysql> SELECT a, b, HEX(a), HEX(b) FROM t1;
+------+------------------------+--------+----------------------+
| a | b | HEX(a) | HEX(b) |
+------+------------------------+--------+----------------------+
| x | 0x78000000000000000000 | 78 | 78000000000000000000 |
| x | 0x78200000000000000000 | 78 | 78200000000000000000 |
+------+------------------------+--------+----------------------+
12.8.6 排序规则效果示例
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-effect.html
示例 1:排序德语 Umlauts
假设表T中的列X具有这些latin1列值:
Muffler
Müller
MX Systems
MySQL
还假设通过以下语句检索列值:
SELECT X FROM T ORDER BY X COLLATE *collation_name*;
使用不同排序规则的ORDER BY,以下表格显示了值的排序结果。
latin1_swedish_ci | latin1_german1_ci | latin1_german2_ci |
|---|---|---|
| 阻尼器 | 阻尼器 | 米勒 |
| MX 系统 | 米勒 | 阻尼器 |
| 米勒 | MX 系统 | MX 系统 |
| MySQL | MySQL | MySQL |
在这个例子中导致不同排序顺序的字符是ü(德语“U-umlaut”)。
-
第一列显示了使用瑞典/芬兰排序规则的
SELECT的结果,该规则表示 U-umlaut 与 Y 排序。 -
第二列显示了使用德国 DIN-1 规则的
SELECT的结果,该规则表示 U-umlaut 与 U 排序。 -
第三列显示了使用德国 DIN-2 规则的
SELECT的结果,该规则表示 U-umlaut 与 UE 排序。
示例 2:搜索德语 Umlauts
假设您有三个仅由字符集和排序规则不同的表:
mysql> SET NAMES utf8mb4;
mysql> CREATE TABLE german1 (
c CHAR(10)
) CHARACTER SET latin1 COLLATE latin1_german1_ci;
mysql> CREATE TABLE german2 (
c CHAR(10)
) CHARACTER SET latin1 COLLATE latin1_german2_ci;
mysql> CREATE TABLE germanutf8 (
c CHAR(10)
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
每个表包含两条记录:
mysql> INSERT INTO german1 VALUES ('Bar'), ('Bär');
mysql> INSERT INTO german2 VALUES ('Bar'), ('Bär');
mysql> INSERT INTO germanutf8 VALUES ('Bar'), ('Bär');
上述排序规则中有两个具有A = Ä的相等性,一个没有这种相等性(latin1_german2_ci)。因此,比较产生了这里显示的结果:
mysql> SELECT * FROM german1 WHERE c = 'Bär';
+------+
| c |
+------+
| Bar |
| Bär |
+------+
mysql> SELECT * FROM german2 WHERE c = 'Bär';
+------+
| c |
+------+
| Bär |
+------+
mysql> SELECT * FROM germanutf8 WHERE c = 'Bär';
+------+
| c |
+------+
| Bar |
| Bär |
+------+
这不是一个错误,而是latin1_german1_ci和utf8mb4_unicode_ci的排序属性的结果(所示的排序是根据德国 DIN 5007 标准进行的)。
12.8.7 在 INFORMATION_SCHEMA 搜索中使用排序规则
原文:
dev.mysql.com/doc/refman/8.0/en/charset-collation-information-schema.html
INFORMATION_SCHEMA表中的字符串列具有utf8mb3_general_ci排序规则,这是不区分大小写的。但是,对于与文件系统中表示的对象对应的值,例如数据库和表,在INFORMATION_SCHEMA字符串列中的搜索可以是区分大小写或不区分大小写,这取决于底层文件系统的特性和lower_case_table_names系统变量设置。例如,如果文件系统区分大小写,则搜索可能是区分大小写的。本节描述了这种行为以及如何在必要时进行修改。
假设一个查询在SCHEMATA.SCHEMA_NAME列中搜索test数据库。在 Linux 上,文件系统区分大小写,因此SCHEMATA.SCHEMA_NAME与'test'的比较匹配,但与'TEST'的比较不匹配:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'TEST';
Empty set (0.00 sec)
这些结果发生在将lower_case_table_names系统变量设置为 0 时。将lower_case_table_names设置为 1 或 2 会导致第二个查询返回与第一个查询相同(非空)的结果。
注意
禁止使用与服务器初始化时使用的设置不同的lower_case_table_names设置启动服务器。
在 Windows 或 macOS 上,文件系统不区分大小写,因此比较匹配'test'和'TEST':
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'TEST';
+-------------+
| SCHEMA_NAME |
+-------------+
| TEST |
+-------------+
在这种情况下,lower_case_table_names的值没有任何区别。
前面的行为发生是因为在搜索与文件系统中表示的对象对应的值时,utf8mb3_general_ci排序规则不用于INFORMATION_SCHEMA查询。
如果对INFORMATION_SCHEMA列的字符串操作的结果与预期不符,则可以使用显式的COLLATE子句来强制使用合适的排序规则(参见第 12.8.1 节,“在 SQL 语句中使用 COLLATE”)。例如,要执行不区分大小写的搜索,请在INFORMATION_SCHEMA列名后使用COLLATE:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME COLLATE utf8mb3_general_ci = 'test';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME COLLATE utf8mb3_general_ci = 'TEST';
+-------------+
| SCHEMA_NAME |
+-------------+
| test |
+-------------+
你也可以使用UPPER()或LOWER()函数:
WHERE UPPER(SCHEMA_NAME) = 'TEST'
WHERE LOWER(SCHEMA_NAME) = 'test'
尽管即使在具有区分大小写文件系统的平台上也可以执行不区分大小写的比较,如上所示,但这并不一定总是正确的做法。在这样的平台上,可能存在仅在大小写不同的名称的多个对象。例如,同时存在名为city、CITY和City的表。考虑搜索是否应匹配所有这些名称或仅匹配一个,并相应地编写查询。以下比较中的第一个(使用utf8mb3_bin)是区分大小写的;其他则不是:
WHERE TABLE_NAME COLLATE utf8mb3_bin = 'City'
WHERE TABLE_NAME COLLATE utf8mb3_general_ci = 'city'
WHERE UPPER(TABLE_NAME) = 'CITY'
WHERE LOWER(TABLE_NAME) = 'city'
在INFORMATION_SCHEMA的字符串列中搜索引用INFORMATION_SCHEMA本身的值时,会使用utf8mb3_general_ci校对规则,因为INFORMATION_SCHEMA是一个在文件系统中没有实际表示的“虚拟”数据库。例如,与SCHEMATA.SCHEMA_NAME的比较会匹配'information_schema'或'INFORMATION_SCHEMA',不受平台影响:
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'information_schema';
+--------------------+
| SCHEMA_NAME |
+--------------------+
| information_schema |
+--------------------+
mysql> SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA
WHERE SCHEMA_NAME = 'INFORMATION_SCHEMA';
+--------------------+
| SCHEMA_NAME |
+--------------------+
| information_schema |
+--------------------+
12.9 Unicode 支持
12.9.1 utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
12.9.2 utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)
12.9.3 utf8 字符集(utf8mb3 的弃用别名)
12.9.4 ucs2 字符集(UCS-2 Unicode 编码)
12.9.5 utf16 字符集(UTF-16 Unicode 编码)
12.9.6 utf16le 字符集(UTF-16LE Unicode 编码)
12.9.7 utf32 字符集(UTF-32 Unicode 编码)
12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
Unicode 标准包括来自基本多语言平面(BMP)和超出 BMP 范围的补充字符。本节描述了 MySQL 中对 Unicode 的支持。有关 Unicode 标准本身的信息,请访问Unicode Consortium 网站。
BMP 字符具有以下特征:
-
它们的代码点值介于 0 和 65535 之间(或
U+0000和U+FFFF)。 -
它们可以使用 8、16 或 24 位(1 到 3 字节)的可变长度编码进行编码。
-
它们可以使用 16 位(2 字节)的固定长度编码进行编码。
-
它们几乎可以涵盖所有主要语言中的所有字符。
补充字符超出 BMP 范围:
-
它们的代码点值介于
U+10000和U+10FFFF之间。 -
对补充字符的 Unicode 支持需要具有超出 BMP 字符范围的范围的字符集,因此比 BMP 字符占用更多的空间(每个字符最多 4 个字节)。
用于编码 Unicode 数据的 UTF-8(8 位单元的 Unicode 转换格式)方法根据 RFC 3629 实现,描述了采用从一个到四个字节的编码序列的编码序列。UTF-8 的理念是使用不同长度的字节序列对各种 Unicode 字符进行编码:
-
基本拉丁字母、数字和标点符号使用一个字节。
-
大多数欧洲和中东文字母适合于 2 字节序列:扩展拉丁字母(带有颚化音符、长音符、重音符、重音符和其他重音符)、西里尔字母、希腊字母、亚美尼亚字母、希伯来字母、阿拉伯字母、叙利亚字母等。
-
韩文、中文和日文表意文字使用 3 字节或 4 字节序列。
MySQL 支持这些 Unicode 字符集:
-
utf8mb4:使用每个字符 1 到 4 个字节的 Unicode 字符集的 UTF-8 编码。 -
utf8mb3:使用每个字符 1 到 3 个字节的 Unicode 字符集的 UTF-8 编码。这个字符集在 MySQL 8.0 中已被弃用,你应该使用utf8mb4。 -
utf8:utf8mb3的别名。在 MySQL 8.0 中,这个别名已被弃用;请改用utf8mb4。预计在未来的版本中,utf8将成为utf8mb4的别名。 -
ucs2:Unicode 字符集的 UCS-2 编码,每个字符使用两个字节。在 MySQL 8.0.28 中已弃用;您应该预期在将来的版本中删除对该字符集的支持。 -
utf16:Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2,但具有补充字符的扩展。 -
utf16le:Unicode 字符集的 UTF-16LE 编码。类似于utf16,但是小端序而不是大端序。 -
utf32:Unicode 字符集的 UTF-32 编码,每个字符使用四个字节。
注意
utf8mb3字符集已被弃用,您应该预期在将来的 MySQL 版本中将其删除。请改用utf8mb4。utf8目前是utf8mb3的别名,但现在已被弃用,预计utf8随后将成为对utf8mb4的引用。从 MySQL 8.0.28 开始,在 Information Schema 表的列和 SQL SHOW语句的输出中,utf8mb3也会显示为utf8的替代项。
另外,在 MySQL 8.0.30 中,所有使用utf8_前缀的校对规则都将改名为utf8mb3_。
为避免关于utf8含义的歧义,考虑明确指定字符集引用为utf8mb4。
表 12.2,“Unicode 字符集的一般特性”总结了 MySQL 支持的 Unicode 字符集的一般特性。
表 12.2 Unicode 字符集的一般特性
| 字符集 | 支持的字符 | 每个字符所需的存储空间 |
|---|---|---|
utf8mb3,utf8(已弃用) | 仅限 BMP | 1、2 或 3 字节 |
ucs2 | 仅限 BMP | 2 字节 |
utf8mb4 | BMP 和补充 | 1、2、3 或 4 字节 |
utf16 | BMP 和补充 | 2 或 4 字节 |
utf16le | BMP 和补充 | 2 或 4 字节 |
utf32 | BMP 和补充 | 4 字节 |
超出 BMP 范围的字符在转换为仅支持 BMP 字符的 Unicode 字符集(utf8mb3或ucs2)时会被视为REPLACEMENT CHARACTER并转换为'?'。
如果您使用支持补充字符且比仅支持 BMP 的utf8mb3和ucs2字符集“更宽”的字符集,您的应用程序可能存在潜在的不兼容性问题;请参阅第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。该部分还描述了如何将表从(3 字节)utf8mb3转换为(4 字节)utf8mb4,以及在这样做时可能适用的约束条件。
大多数 Unicode 字符集都有类似的排序规则集。例如,每个字符集都有一个丹麦排序规则,其名称分别为utf8mb4_danish_ci、utf8mb3_danish_ci(已弃用)、utf8_danish_ci(已弃用)、ucs2_danish_ci、utf16_danish_ci和utf32_danish_ci。唯一的例外是utf16le,它只有两个排序规则。有关 Unicode 排序规则及其区分特性的信息,包括辅助字符的排序规则属性,请参阅第 12.10.1 节,“Unicode 字符集”。
MySQL 对于 UCS-2、UTF-16 和 UTF-32 的实现以大端字节顺序存储字符,并且在数值开头不使用字节顺序标记(BOM)。其他数据库系统可能使用小端字节顺序或者 BOM。在这种情况下,在这些系统和 MySQL 之间传输数据时需要执行数值转换。UTF-16LE 的实现是小端字节顺序。
MySQL 对于 UTF-8 数值不使用 BOM。
与服务器使用 Unicode 通信的客户端应该相应地设置客户端字符集(例如,通过发出SET NAMES 'utf8mb4'语句)。有些字符集不能用作客户端字符集。尝试在SET NAMES或SET CHARACTER SET中使用它们会产生错误。请参阅不允许的客户端字符集。
以下章节提供了关于 MySQL 中 Unicode 字符集的额外细节。
12.9.1 utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb4.html
utf8mb4字符集具有以下特点:
-
支持 BMP 和补充字符。
-
每个多字节字符最多需要四个字节。
utf8mb4与仅支持 BMP 字符并且每个字符最多使用三个字节的utf8mb3字符集形成对比:
-
对于 BMP 字符,
utf8mb4和utf8mb3具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf8mb4需要四个字节来存储,而utf8mb3根本无法存储该字符。当将utf8mb3列转换为utf8mb4时,您无需担心转换补充字符,因为根本没有。
utf8mb4是utf8mb3的超集,因此对于诸如以下连接操作,结果具有字符集utf8mb4和utf8mb4_col的排序规则:
SELECT CONCAT(utf8mb3_col, utf8mb4_col);
同样,WHERE子句中的以下比较按照utf8mb4_col的排序规则进行:
SELECT * FROM utf8mb3_tbl, utf8mb4_tbl
WHERE utf8mb3_tbl.utf8mb3_col = utf8mb4_tbl.utf8mb4_col;
关于与多字节字符集相关的数据类型存储信息,请参阅字符串类型存储要求。
12.9.2 utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)
译文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb3.html
utf8mb3字符集具有以下特点:
-
仅支持 BMP 字符(不支持补充字符)
-
每个多字节字符最多需要三个字节。
使用 UTF-8 数据但需要支持补充字符的应用程序应该使用utf8mb4而不是utf8mb3(参见第 12.9.1 节,“utf8mb4 字符集(4 字节 UTF-8 Unicode 编码)”)。
utf8mb3和ucs2中提供完全相同的字符集。也就是说,它们具有相同的 repertoire。
注意
MySQL 推荐的字符集是utf8mb4。所有新应用程序应该使用utf8mb4。
utf8mb3字符集已被弃用。utf8mb3将在 MySQL 8.0.x 及其后续 LTS 版本系列的生命周期中继续受支持,以及在 MySQL 8.0 中。
预计utf8mb3将在 MySQL 的未来主要版本中被移除。
由于更改字符集可能是一个复杂且耗时的任务,您应该立即开始准备使用utf8mb4来为新应用程序做好准备。有关转换使用 utfmb3 的现有应用程序的指导,请参见第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。
utf8mb3可以在CHARACTER SET子句中使用,而utf8mb3_*collation_substring*可以在COLLATE子句中使用,其中*collation_substring*是bin、czech_ci、danish_ci、esperanto_ci、estonian_ci等。例如:
CREATE TABLE t (s1 CHAR(1)) CHARACTER SET utf8mb3;
SELECT * FROM t WHERE s1 COLLATE utf8mb3_general_ci = 'x';
DECLARE x VARCHAR(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_danish_ci;
SELECT CAST('a' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_czech_ci;
在 MySQL 8.0.29 之前,语句中的utf8mb3实例会被转换为utf8。在 MySQL 8.0.30 及更高版本中,情况相反,因此在SHOW CREATE TABLE或SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS或SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS等语句中,用户会看到以utf8mb3或utf8mb3_为前缀的字符集或校对名称。
utf8mb3在CHARACTER SET子句以外的上下文中也是有效的(但已弃用)。例如:
mysqld --character-set-server=utf8mb3
SET NAMES 'utf8mb3'; /* and other SET statements that have similar effect */
SELECT _utf8mb3 'a';
有关与多字节字符集相关的数据类型存储的信息,请参见字符串类型存储要求。
12.9.3 utf8 字符集(utf8mb3 的弃用别名)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8.html
MySQL 过去曾将utf8用作utf8mb3字符集的别名,但现在已弃用此用法;在 MySQL 8.0 中,SHOW语句和INFORMATION_SCHEMA表的列显示为utf8mb3。有关更多信息,请参见第 12.9.2 节,“utf8mb3 字符集(3 字节 UTF-8 Unicode 编码)”。
注意
MySQL 推荐的字符集是utf8mb4。所有新应用程序应该使用utf8mb4。
utf8mb3字符集已被弃用。utf8mb3将在 MySQL 8.0.x 及其后续 LTS 版本系列的生命周期中继续受支持,以及在 MySQL 8.0 中。
预计utf8mb3将在 MySQL 的未来主要版本中被移除。
由于更改字符集可能是一个复杂且耗时的任务,您应该立即开始准备使用utf8mb4来为新应用程序做好准备。有关转换现有使用 utfmb3 的应用程序的指导,请参见第 12.9.8 节,“在 3 字节和 4 字节 Unicode 字符集之间转换”。
12.9.4 ucs2字符集(UCS-2 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-ucs2.html
注意
ucs2字符集在 MySQL 8.0.28 中已被弃用;预计将在未来的 MySQL 版本中移除。请改用utf8mb4。
在 UCS-2 中,每个字符由一个 2 字节的 Unicode 代码表示,最高有效字节在前。例如:LATIN CAPITAL LETTER A的代码为0x0041,存储为一个 2 字节序列:0x00 0x41。CYRILLIC SMALL LETTER YERU(Unicode 0x044B)存储为一个 2 字节序列:0x04 0x4B。有关 Unicode 字符及其代码,请参考Unicode Consortium website。
ucs2字符集具有以下特点:
-
仅支持 BMP 字符(不支持补充字符)
-
使用固定长度的 16 位编码,每个字符需要两个字节。
12.9.5 utf16字符集(UTF-16 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf16.html
utf16字符集是ucs2字符集的扩展,使其能够编码补充字符:
-
对于 BMP 字符,
utf16和ucs2具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf16有一个特殊的序列来使用 32 位表示字符。这被称为“代理”机制:对于大于0xffff的数字,取 10 位并将它们加到0xd800,放入第一个 16 位字中,再取 10 位并将它们加到0xdc00,放入下一个 16 位字中。因此,所有补充字符需要 32 位,其中前 16 位是介于0xd800和0xdbff之间的数字,后 16 位是介于0xdc00和0xdfff之间的数字。示例在 Unicode 4.0 文档的第15.5 代理区中。
因为utf16支持代理而ucs2不支持,只有在utf16中才适用的有效性检查:您不能插入顶部代理而没有底部代理,反之亦然。例如:
INSERT INTO t (ucs2_column) VALUES (0xd800); /* legal */
INSERT INTO t (utf16_column)VALUES (0xd800); /* illegal */
对于技术上有效但不是真正 Unicode 的字符,没有有效性检查(即 Unicode 认为是“未分配代码点”或“私有使用”字符甚至“非法”字符,如0xffff)。例如,由于U+F8FF是苹果 Logo,这是合法的:
INSERT INTO t (utf16_column)VALUES (0xf8ff); /* legal */
这些字符不能期望对每个人都有相同的含义。
因为 MySQL 必须考虑最坏情况(一个字符需要四个字节),utf16列或索引的最大长度仅为ucs2列或索引的最大长度的一半。例如,MEMORY表索引键的最大长度为 3072 字节,因此这些语句创建具有ucs2和utf16列的最长允许索引的表:
CREATE TABLE tf (s1 VARCHAR(1536) CHARACTER SET ucs2) ENGINE=MEMORY;
CREATE INDEX i ON tf (s1);
CREATE TABLE tg (s1 VARCHAR(768) CHARACTER SET utf16) ENGINE=MEMORY;
CREATE INDEX i ON tg (s1);
12.9.6 utf16le 字符集(UTF-16LE Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf16le.html
这与utf16相同,但是采用小端序而不是大端序。
12.9.7 utf32 字符集(UTF-32 Unicode 编码)
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf32.html
utf32字符集是固定长度的(类似于ucs2,不同于utf16)。utf32为每个字符使用 32 位,不同于ucs2(每个字符使用 16 位),也不同于utf16(某些字符使用 16 位,某些使用 32 位)。
utf32占用的空间是ucs2的两倍,比utf16更多,但utf32和ucs2一样具有存储的优势:utf32所需的字节数等于字符数乘以 4。此外,与utf16不同,utf32没有编码技巧,因此存储的值等于代码值。
为了展示后一种优势的用处,这里有一个示例,展示如何根据utf32的代码值确定一个utf8mb4的值:
/* Assume code value = 100cc LINEAR B WHEELED CHARIOT */
CREATE TABLE tmp (utf32_col CHAR(1) CHARACTER SET utf32,
utf8mb4_col CHAR(1) CHARACTER SET utf8mb4);
INSERT INTO tmp VALUES (0x000100cc,NULL);
UPDATE tmp SET utf8mb4_col = utf32_col;
SELECT HEX(utf32_col),HEX(utf8mb4_col) FROM tmp;
MySQL 对未分配的 Unicode 字符或专用区域字符的添加非常宽容。实际上,utf32只有一个有效性检查:没有代码值可以大于0x10ffff。例如,这是不合法的:
INSERT INTO t (utf32_column) VALUES (0x110000); /* illegal */
12.9.8 在 3 字节和 4 字节 Unicode 字符集之间转换
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-conversion.html
本节描述了在utf8mb3和utf8mb4字符集之间转换字符数据时可能遇到的问题。
注意
本讨论主要集中在utf8mb3和utf8mb4之间的转换,但类似的原则也适用于ucs2字符集与utf16或utf32等字符集之间的转换。
utf8mb3和utf8mb4字符集的区别如下:
-
utf8mb3仅支持基本多文种平面(BMP)中的字符。utf8mb4还支持位于 BMP 之外的补充字符。 -
utf8mb3每个字符最多使用三个字节。utf8mb4每个字符最多使用四个字节。
注意
本讨论提到utf8mb3和utf8mb4字符集名称,明确指代 3 字节和 4 字节 UTF-8 字符集数据。
从utf8mb3转换为utf8mb4的一个优势是,这使应用程序能够使用补充字符。一个权衡是这可能增加数据存储空间的需求。
在表内容方面,从utf8mb3转换为utf8mb4没有问题:
-
对于 BMP 字符,
utf8mb4和utf8mb3具有相同的存储特性:相同的代码值,相同的编码,相同的长度。 -
对于补充字符,
utf8mb4需要四个字节来存储它,而utf8mb3根本无法存储该字符。当将utf8mb3列转换为utf8mb4时,您不必担心转换补充字符,因为根本没有。
在表结构方面,这些是主要的潜在不兼容性:
-
对于可变长度字符数据类型(
VARCHAR和TEXT类型),在utf8mb4列中允许的最大字符长度比在utf8mb3列中要少。 -
对于所有字符数据类型(
CHAR、VARCHAR和TEXT类型),在utf8mb4列中可以索引的最大字符数比在utf8mb3列中要少。
因此,要将表从utf8mb3转换为utf8mb4,可能需要更改一些列或索引定义。
可以使用ALTER TABLE将表从utf8mb3转换为utf8mb4。假设一个表具有这样的定义:
CREATE TABLE t1 (
col1 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_unicode_ci NOT NULL,
col2 CHAR(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL
) CHARACTER SET utf8mb3;
以下语句将t1转换为使用utf8mb4:
ALTER TABLE t1
DEFAULT CHARACTER SET utf8mb4,
MODIFY col1 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
MODIFY col2 CHAR(10)
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
从utf8mb3转换为utf8mb4的关键在于列或索引键的最大长度在字节方面保持不变。因此,在字符方面较小,因为字符的最大长度为四个字节而不是三个字节。对于CHAR、VARCHAR和TEXT数据类型,在转换 MySQL 表时,请注意以下问题:
-
检查所有
utf8mb3列的定义,并确保其不超过存储引擎的最大长度。 -
检查所有
utf8mb3列上的索引,并确保其不超过存储引擎的最大长度。有时,由于存储引擎的增强,最大长度可能会发生变化。
如果满足上述条件,则必须减少列或索引的定义长度,或者继续使用utf8mb3而不是utf8mb4。
以下是可能需要进行结构更改的一些示例:
-
一个
TINYTEXT列最多可以容纳 255 个字节,因此可以容纳 85 个 3 字节或 63 个 4 字节字符。假设您有一个使用utf8mb3但必须能够包含超过 63 个字符的TINYTEXT列。除非还将数据类型更改为更长的类型,如TEXT,否则无法将其转换为utf8mb4。同样,如果要将非常长的
VARCHAR列从utf8mb3转换为utf8mb4,可能需要将其更改为更长的TEXT类型之一。 -
对于使用
COMPACT或REDUNDANT行格式的表,InnoDB对于utf8mb3或utf8mb4列的最大索引长度为 767 个字节,因此对于分别最多可以索引 255 或 191 个字符的utf8mb3或utf8mb4列。如果您当前具有超过 191 个字符的utf8mb3列索引,则必须索引较少数量的字符。在使用
COMPACT或REDUNDANT行格式的InnoDB表中,这些列和索引定义是合法的:col1 VARCHAR(500) CHARACTER SET utf8mb3, INDEX (col1(255))要改用
utf8mb4,索引必须更小:col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))注意
对于使用
COMPRESSED或DYNAMIC行格式的InnoDB表,允许索引键前缀的长度超过 767 字节(最多 3072 字节)。使用这些行格式创建的表允许您为utf8mb3或utf8mb4列最多索引 1024 或 768 个字符。有关相关信息,请参见第 17.22 节,“InnoDB 限制”和 DYNAMIC 行格式。
前述类型的更改只有在您有非常长的列或索引时才可能需要。否则,您应该能够在不出现问题的情况下将表从utf8mb3转换为utf8mb4,如前所述使用ALTER TABLE。
以下项目总结了其他潜在的不兼容性:
-
SET NAMES 'utf8mb4'导致连接字符集使用 4 字节字符集。只要服务器不发送 4 字节字符,就不应该有问题。否则,期望每个字符接收最多三个字节的应用程序可能会出现问题。相反,期望发送 4 字节字符的应用程序必须确保服务器理解它们。 -
对于复制,如果要在源上使用支持补充字符的字符集,则所有副本必须也理解它们。
此外,请记住一个一般原则,即如果表在源和副本上有不同的定义,这可能导致意外结果。例如,在源上使用
utf8mb3和在副本上使用utf8mb4会导致最大索引键长度的差异,这样做是有风险的。
如果您已经转换为utf8mb4、utf16、utf16le或utf32,然后决定转换回utf8mb3或ucs2(例如,降级到 MySQL 的旧版本),则应考虑以下事项:
-
utf8mb3和ucs2数据应该没有问题。 -
服务器必须足够新,以识别引用正在转换的字符集的定义。
-
对于引用
utf8mb4字符集的对象定义,您可以在降级之前使用mysqldump进行转储,编辑转储文件以将utf8mb4实例更改为utf8,然后在旧服务器中重新加载文件,只要数据中没有 4 字节字符。旧服务器在转储文件对象定义中看到utf8,并创建使用(3 字节)utf8字符集的新对象。
12.10 支持的字符集和排序规则
12.10.1 Unicode 字符集
12.10.2 西欧字符集
12.10.3 中欧字符集
12.10.4 南欧和中东字符集
12.10.5 波罗的海字符集
12.10.6 斯拉夫字符集
12.10.7 亚洲字符集
12.10.8 二进制字符集
本节指示了 MySQL 支持的字符集。每个相关字符集组都有一个子节。对于每个字符集,列出了可接受的排序规则。
要列出可用的字符集及其默认排序规则,请使用SHOW CHARACTER SET语句或查询INFORMATION_SCHEMA CHARACTER_SETS表。例如:
mysql> SHOW CHARACTER SET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 |
| ascii | US ASCII | ascii_general_ci | 1 |
| big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 |
| binary | Binary pseudo charset | binary | 1 |
| cp1250 | Windows Central European | cp1250_general_ci | 1 |
| cp1251 | Windows Cyrillic | cp1251_general_ci | 1 |
| cp1256 | Windows Arabic | cp1256_general_ci | 1 |
| cp1257 | Windows Baltic | cp1257_general_ci | 1 |
| cp850 | DOS West European | cp850_general_ci | 1 |
| cp852 | DOS Central European | cp852_general_ci | 1 |
| cp866 | DOS Russian | cp866_general_ci | 1 |
| cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 |
| dec8 | DEC West European | dec8_swedish_ci | 1 |
| eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 |
| euckr | EUC-KR Korean | euckr_korean_ci | 2 |
| gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 |
| gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 |
| gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 |
| geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 |
| greek | ISO 8859-7 Greek | greek_general_ci | 1 |
| hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 |
| hp8 | HP West European | hp8_english_ci | 1 |
| keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 |
| koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 |
| koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 |
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 |
| latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 |
| latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 |
| macce | Mac Central European | macce_general_ci | 1 |
| macroman | Mac West European | macroman_general_ci | 1 |
| sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 |
| swe7 | 7bit Swedish | swe7_swedish_ci | 1 |
| tis620 | TIS620 Thai | tis620_thai_ci | 1 |
| ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 |
| ujis | EUC-JP Japanese | ujis_japanese_ci | 3 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
| utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 |
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
+----------+---------------------------------+---------------------+--------+
对于一个字符集有多个排序规则的情况,可能不清楚哪个排序规则最适合特定应用程序。为了避免选择错误的排序规则,可以通过一些比较具有代表性的数据值来确保给定的排序规则对值进行排序的方式符合您的期望。
12.10.1 Unicode 字符集
原文:
dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html
本节描述了 Unicode 字符集可用的排序规则及其区分特性。有关 Unicode 的一般信息,请参见第 12.9 节,“Unicode 支持”。
MySQL 支持多个 Unicode 字符集:
-
utf8mb4: 使用每个字符一到四个字节的 Unicode 字符集的 UTF-8 编码。 -
utf8mb3: 使用每个字符一到三个字节的 Unicode 字符集的 UTF-8 编码。此字符集在 MySQL 8.0 中已弃用,您应该改用utf8mb4。 -
utf8: 对utf8mb3的别名。在 MySQL 8.0 中,此别名已被弃用;请改用utf8mb4。预计在将来的版本中,utf8将成为utf8mb4的别名。 -
ucs2: 使用每个字符两个字节的 Unicode 字符集的 UCS-2 编码。在 MySQL 8.0.28 中已弃用;您应该预期在将来的版本中删除对此字符集的支持。 -
utf16: Unicode 字符集的 UTF-16 编码,每个字符使用两个或四个字节。类似于ucs2但具有用于补充字符的扩展。 -
utf16le: Unicode 字符集的 UTF-16LE 编码。类似于utf16但是小端序而不是大端序。 -
utf32: 使用每个字符四个字节的 UTF-32 编码的 Unicode 字符集。
注意
utf8mb3字符集已被弃用,您应该预期在将来的 MySQL 版本中将其移除。请改用utf8mb4。utf8目前是utf8mb3的别名,但现在已被弃用,utf8预计随后将成为utf8mb4的引用。从 MySQL 8.0.28 开始,在 Information Schema 表的列和 SQL SHOW语句的输出中,utf8mb3也会显示为utf8的替代项。
为了避免关于utf8含义的歧义,考虑在字符集引用中明确指定utf8mb4。
utf8mb4、utf16、utf16le和utf32支持基本多文种平面(BMP)字符和超出 BMP 范围的补充字符。utf8mb3和ucs2仅支持 BMP 字符。
大多数 Unicode 字符集都有一般排序规则(名称中带有_general或没有语言说明符号),二进制排序规则(名称中带有_bin),以及几种特定语言的排序规则(带有语言说明符号)。例如,对于utf8mb4,utf8mb4_general_ci和utf8mb4_bin是其一般和二进制排序规则,而utf8mb4_danish_ci是其特定语言之一的排序规则。
大多数字符集具有单一的二进制排序。utf8mb4 是一个例外,它有两个:utf8mb4_bin 和(从 MySQL 8.0.17 开始)utf8mb4_0900_bin。这两个二进制排序具有相同的排序顺序,但通过它们的填充属性和排序权重特性进行区分。参见 排序填充属性 和 字符排序权重。
utf16le 的排序支持有限。唯一可用的排序是 utf16le_general_ci 和 utf16le_bin。这些与 utf16_general_ci 和 utf16_bin 类似。
-
Unicode Collation Algorithm (UCA) 版本 版本")
-
排序填充属性
-
特定语言排序
-
_general_ci 与 _unicode_ci 排序
-
字符排序权重
-
杂项信息
Unicode Collation Algorithm (UCA) 版本
MySQL 根据 www.unicode.org/reports/tr10/ 中描述的 Unicode Collation Algorithm (UCA) 实现 *xxx*_unicode_ci 排序。该排序使用版本-4.0.0 UCA 权重键:www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt。*xxx*_unicode_ci 排序对 Unicode Collation Algorithm 仅有部分支持。某些字符不受支持,组合标记也没有完全支持。这影响到越南语、约鲁巴语和纳瓦霍语等语言。在字符串比较中,组合字符被视为与使用单个 Unicode 字符写的相同字符不同,并且这两个字符被认为具有不同的长度(例如,由 CHAR_LENGTH() 函数返回或在结果集元数据中返回)。
基于高于 4.0.0 的 UCA 版本的 Unicode 排序在排序名称中包含版本。例如:
-
utf8mb4_unicode_520_ci基于 UCA 5.2.0 权重键 (www.unicode.org/Public/UCA/5.2.0/allkeys.txt), -
utf8mb4_0900_ai_ci基于 UCA 9.0.0 权重键 (www.unicode.org/Public/UCA/9.0.0/allkeys.txt).
LOWER()和UPPER()函数根据其参数的校对执行大小写折叠。如果一个字符只有在 Unicode 版本高于 4.0.0 中才有大写和小写版本,则这些函数只会在参数校对使用足够高的 UCA 版本时转换该字符。
校对填充属性
基于 UCA 9.0.0 及更高版本的校对比基于 UCA 9.0.0 之前版本的校对更快。它们的填充属性也是NO PAD,与基于 UCA 9.0.0 之前版本的校对中使用的PAD SPACE相反。对于非二进制字符串的比较,NO PAD校对将字符串末尾的空格视为任何其他字符(参见比较中的尾随空格处理)。
要确定校对的填充属性,请使用INFORMATION_SCHEMA的COLLATIONS表,该表具有PAD_ATTRIBUTE列。例如:
mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE CHARACTER_SET_NAME = 'utf8mb4';
+----------------------------+---------------+
| COLLATION_NAME | PAD_ATTRIBUTE |
+----------------------------+---------------+
| utf8mb4_general_ci | PAD SPACE |
| utf8mb4_bin | PAD SPACE |
| utf8mb4_unicode_ci | PAD SPACE |
| utf8mb4_icelandic_ci | PAD SPACE |
...
| utf8mb4_0900_ai_ci | NO PAD |
| utf8mb4_de_pb_0900_ai_ci | NO PAD |
| utf8mb4_is_0900_ai_ci | NO PAD |
...
| utf8mb4_ja_0900_as_cs | NO PAD |
| utf8mb4_ja_0900_as_cs_ks | NO PAD |
| utf8mb4_0900_as_ci | NO PAD |
| utf8mb4_ru_0900_ai_ci | NO PAD |
| utf8mb4_ru_0900_as_cs | NO PAD |
| utf8mb4_zh_0900_as_cs | NO PAD |
| utf8mb4_0900_bin | NO PAD |
+----------------------------+---------------+
具有NO PAD校对的非二进制字符串值(CHAR,VARCHAR和TEXT)与其他校对在尾随空格方面有所不同。例如,'a'和'a '比较为不同的字符串,而不是相同的字符串。可以使用utf8mb4的二进制校对来看到这一点。utf8mb4_bin的填充属性是PAD SPACE,而utf8mb4_0900_bin的填充属性是NO PAD。因此,涉及utf8mb4_0900_bin的操作不会添加尾随空格,并且涉及具有尾随空格的字符串的比较可能会因为两种校对而有所不同:
mysql> CREATE TABLE t1 (c CHAR(10) COLLATE utf8mb4_bin);
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO t1 VALUES('a');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM t1 WHERE c = 'a ';
+------+
| c |
+------+
| a |
+------+
1 row in set (0.00 sec)
mysql> ALTER TABLE t1 MODIFY c CHAR(10) COLLATE utf8mb4_0900_bin;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t1 WHERE c = 'a ';
Empty set (0.00 sec)
语言特定的校对
如果仅基于 Unicode 校对算法(UCA)的排序对某种语言效果不佳,MySQL 会实现语言特定的 Unicode 校对。语言特定的校对是基于 UCA 的,具有额外的语言定制规则。此类规则的示例稍后在本节中出现。有关特定语言排序的问题,unicode.org提供了通用语言环境数据存储库(CLDR)校对图表,网址为www.unicode.org/cldr/charts/30/collation/index.html。
例如,非语言特定的utf8mb4_0900_ai_ci和语言特定的utf8mb4_*LOCALE*_0900_ai_ci Unicode 校对具有以下特点:
-
校对基于 UCA 9.0.0 和 CLDR v30,是不区分重音和大小写的。这些特征在校对名称中用
_0900,_ai和_ci表示。例外:utf8mb4_la_0900_ai_ci不是基于 CLDR,因为古典拉丁语在 CLDR 中未定义。 -
校对适用于范围[U+0, U+10FFFF]中的所有字符。
-
如果排序规则不是特定于语言的,它会按照默认顺序(如下所述)对所有字符进行排序,包括补充字符。如果排序规则是特定于语言的,它会根据特定于语言的规则正确对该语言的字符进行排序,并对不属于该语言的字符按默认顺序排序。
-
默认情况下,排序规则根据 DUCET 表(默认 Unicode 排序元素表)中列出的代码点对字符进行排序,根据表中分配的权重值。排序规则根据 UCA 构造的隐式权重值对未在 DUCET 表中列出代码点的字符进行排序。
-
对于非特定于语言的排序规则,缩约序列中的字符被视为单独的字符。对于特定于语言的排序规则,缩约可能会改变字符的排序顺序。
包含在下表中显示的区域代码或语言名称的排序规则名称是特定于语言的排序规则。Unicode 字符集可能包括一个或多个这些语言的排序规则。
表 12.3 Unicode 排序语言标识符
| 语言 | 语言标识符 |
|---|---|
| 波斯尼亚语 | bs |
| 保加利亚语 | bg |
| 中文 | zh |
| 古典拉丁语 | la 或 roman |
| 克罗地亚语 | hr 或 croatian |
| 捷克语 | cs 或 czech |
| 丹麦语 | da 或 danish |
| 世界语 | eo 或 esperanto |
| 爱沙尼亚语 | et 或 estonian |
| 加利西亚语 | gl |
| 德语电话簿排序 | de_pb 或 german2 |
| 匈牙利语 | hu 或 hungarian |
| 冰岛语 | is 或 icelandic |
| 日语 | ja |
| 拉脱维亚语 | lv 或 latvian |
| 立陶宛语 | lt 或 lithuanian |
| 蒙古语 | mn |
| 挪威语 / 书面挪威语 | nb |
| 挪威语 / 新挪威语 | nn |
| 波斯语 | persian |
| 波兰语 | pl 或 polish |
| 罗马尼亚语 | ro 或 romanian |
| 俄语 | ru |
| 塞尔维亚语 | sr |
| 僧伽罗语 | sinhala |
| 斯洛伐克语 | sk 或 slovak |
| 斯洛文尼亚语 | sl 或 slovenian |
| 现代西班牙语 | es 或 spanish |
| 传统西班牙语 | es_trad 或 spanish2 |
| 瑞典语 | sv 或 swedish |
| 土耳其语 | tr 或 turkish |
| 越南语 | vi 或 vietnamese |
| 语言 | 语言标识符 |
MySQL 8.0.30 及更高版本提供了保加利亚语排序规则 utf8mb4_bg_0900_ai_ci 和 utf8mb4_bg_0900_as_cs。
克罗地亚排序规则专为以下克罗地亚字母定制:Č、Ć、Dž、Đ、Lj、Nj、Š、Ž。
MySQL 8.0.30 及更高版本为塞尔维亚语提供了 utf8mb4_sr_latn_0900_ai_ci 和 utf8mb4_sr_latn_0900_as_cs 排序规则,为波斯尼亚语提供了 utf8mb4_bs_0900_ai_ci 和 utf8mb4_bs_0900_as_cs 排序规则,当这些语言使用拉丁字母书写时。
从 MySQL 8.0.30 开始,MySQL 为挪���的两种主要变体提供了排序规则:对于书面挪威语,您可以使用 utf8mb4_nb_0900_ai_ci 和 utf8mb4_nb_0900_as_cs;对于新挪威语,MySQL 现在提供了 utf8mb4_nn_0900_ai_ci 和 utf8mb4_nn_0900_as_cs。
对于日语,utf8mb4字符集包括utf8mb4_ja_0900_as_cs和utf8mb4_ja_0900_as_cs_ks校对。这两种校对都是区分重音和区分大小写的。utf8mb4_ja_0900_as_cs_ks还区分假名,将片假名字符与平假名字符区分开,而utf8mb4_ja_0900_as_cs将片假名和平假名字符视为排序相等。需要日语校对但不需要假名敏感性的应用程序可以使用utf8mb4_ja_0900_as_cs以获得更好的排序性能。utf8mb4_ja_0900_as_cs使用三个权重级别进行排序;utf8mb4_ja_0900_as_cs_ks使用四个。
对于不区分重音的古典拉丁校对,I和J视为相等,U和V视为相等。I和J,以及U和V在基本字母级别上视为相等。换句话说,J被视为带重音的I,U被视为带重音的V。
MySQL 8.0.30 及更高版本提供了蒙古语的校对,使用西里尔字母书写,utf8mb4_mn_cyrl_0900_ai_ci和utf8mb4_mn_cyrl_0900_as_cs。
西班牙语校对适用于现代和传统西班牙语。对于两者,ñ(n-tilde)是n和o之间的单独字母。此外,对于传统西班牙语,ch是c和d之间的单独字母,ll是l和m之间的单独字母。
传统西班牙语校对也可用于阿斯图里亚斯语和加利西亚语。从 MySQL 8.0.30 开始,MySQL 还为加利西亚语提供了utf8mb4_gl_0900_ai_ci和utf8mb4_gl_0900_as_cs校对(这些校对与utf8mb4_es_0900_ai_ci和utf8mb4_es_0900_as_cs相同)。
瑞典校对包括瑞典规则。例如,在瑞典语中,以下关系成立,这是德语或法语说话者所不期望的:
Ü = Y < Ö
_general_ci 与 _unicode_ci 校对
对于任何 Unicode 字符集,使用*xxx*_general_ci校对的操作比*xxx*_unicode_ci校对的操作更快。例如,utf8mb4_general_ci校对的比较速度更快,但略微不够准确,比utf8mb4_unicode_ci校对的比较速度更快。原因是utf8mb4_unicode_ci支持映射,例如扩展;也就是说,当一个字符与其他字符的组合相等时。例如,在德语和其他一些语言中,ß等于ss。utf8mb4_unicode_ci还支持缩写和可忽略字符。utf8mb4_general_ci是一个不支持扩展、缩写或可忽略字符的传统校对。它只能在字符之间进行一对一的比较。
进一步说明,在utf8mb4_general_ci和utf8mb4_unicode_ci中以下相等性成立(对于比较或搜索的影响,请参阅第 12.8.6 节,“校对效果示例”):
Ä = A
Ö = O
Ü = U
校对规则之间的一个区别是对于utf8mb4_general_ci是真实的:
ß = s
而对于支持德国 DIN-1 排序(也称为字典顺序)的utf8mb4_unicode_ci是真实的:
ß = ss
如果使用utf8mb4_unicode_ci的排序对某种语言不起作用,MySQL 会实现特定语言的 Unicode 校对规则。例如,utf8mb4_unicode_ci适用于德语字典顺序和法语,因此不需要创建特殊的utf8mb4校对规则。
utf8mb4_general_ci对于德语和法语都是令人满意的,除了ß等于s,而不等于ss。如果这对您的应用程序可接受,应该使用utf8mb4_general_ci因为它更快。如果这不可接受(例如,如果需要德语字典顺序),应该使用utf8mb4_unicode_ci因为它更准确。
如果需要德国 DIN-2(电话簿)排序,请使用utf8mb4_german2_ci校对规则,它将以下字符集视为相等:
Ä = Æ = AE
Ö = Œ = OE
Ü = UE
ß = ss
utf8mb4_german2_ci类似于latin1_german2_ci,但后者不将Æ视为等于AE或Œ视为等于OE。对于德语字典顺序,没有对应于latin1_german_ci的utf8mb4_german_ci,因为utf8mb4_general_ci已经足够。
字符排序权重
字符的排序权重确定如下:
-
对于除
_bin(二进制)校对规则之外的所有 Unicode 校对规则,MySQL 执行表查找以找到字符的排序权重。 -
对于除
utf8mb4_0900_bin之外的_bin校对规则,权重基于代码点,可能会添加前导零字节。 -
对于
utf8mb4_0900_bin,权重是utf8mb4编码的字节。排序顺序与utf8mb4_bin相同,但速度更快。
可以使用WEIGHT_STRING()函数显示排序权重。(参见第 14.8 节,“字符串函数和运算符”。)如果校对规则使用权重查找表,但某个字符不在表中(例如,因为它是一个“新”字符),排序权重的确定变得更加复杂:
-
对于一般校对规则中的 BMP 字符(
*xxx*_general_ci),权重是代码点。 -
对于 UCA 校对规则中的 BMP 字符(例如
*xxx*_unicode_ci和特定语言的校对规则),应用以下算法:if (code >= 0x3400 && code <= 0x4DB5) base= 0xFB80; /* CJK Ideograph Extension */ else if (code >= 0x4E00 && code <= 0x9FA5) base= 0xFB40; /* CJK Ideograph */ else base= 0xFBC0; /* All other characters */ aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;结果是两个排序元素的序列,
aaaa后跟bbbb。例如:mysql> SELECT HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci)); +----------------------------------------------------------+ | HEX(WEIGHT_STRING(_ucs2 0x04CF COLLATE ucs2_unicode_ci)) | +----------------------------------------------------------+ | FBC084CF | +----------------------------------------------------------+因此,
U+04cf CYRILLIC SMALL LETTER PALOCHKA(ӏ)在所有 UCA 4.0.0 校对规则中都大于U+04c0 CYRILLIC LETTER PALOCHKA(Ӏ)。对于 UCA 5.2.0 校对规则,所有帕洛奇卡字符一起排序。 -
对于一般校对规则中的补充字符,权重是
0xfffd REPLACEMENT CHARACTER的权重。对于 UCA 4.0.0 校对规则中的补充字符,它们的排序权重是0xfffd。也就是说,对于 MySQL 来说,所有补充字符彼此相等,并且大于几乎所有 BMP 字符。使用 Deseret 字符和
COUNT(DISTINCT)的示例:CREATE TABLE t (s1 VARCHAR(5) CHARACTER SET utf32 COLLATE utf32_unicode_ci); INSERT INTO t VALUES (0xfffd); /* REPLACEMENT CHARACTER */ INSERT INTO t VALUES (0x010412); /* DESERET CAPITAL LETTER BEE */ INSERT INTO t VALUES (0x010413); /* DESERET CAPITAL LETTER TEE */ SELECT COUNT(DISTINCT s1) FROM t;结果为 2,因为在 MySQL
*xxx*_unicode_ci校对中,替换字符的权重为0x0dc6,而 Deseret Bee 和 Deseret Tee 的权重均为0xfffd。(如果使用utf32_general_ci校对,则结果为 1,因为在该校对中,这三个字符的权重均为0xfffd。)使用楔形文字字符和
WEIGHT_STRING()的示例:/* The four characters in the INSERT string are 00000041 # LATIN CAPITAL LETTER A 0001218F # CUNEIFORM SIGN KAB 000121A7 # CUNEIFORM SIGN KISH 00000042 # LATIN CAPITAL LETTER B */ CREATE TABLE t (s1 CHAR(4) CHARACTER SET utf32 COLLATE utf32_unicode_ci); INSERT INTO t VALUES (0x000000410001218f000121a700000042); SELECT HEX(WEIGHT_STRING(s1)) FROM t;结果为:
0E33 FFFD FFFD 0E4A0E33和0E4A是 UCA 4.0.0 中的主要权重。FFFD是 KAB 和 KISH 的权重。所有补充字符相等的规则并非最佳选择,但不会引起问题。这些字符非常罕见,因此很少出现多字符字符串完全由补充字符组成。在日本,由于补充字符是晦涩的汉字表意文字,典型用户无论如何都不在乎它们的顺序。如果您真的希望按照 MySQL 规则和其次按照代码点值对行进行排序,那很容易实现:
ORDER BY s1 COLLATE utf32_unicode_ci, s1 COLLATE utf32_bin -
对于基于高于 4.0.0 版本的 UCA 的补充字符(例如,
*xxx*_unicode_520_ci),补充字符不一定都具有相同的排序权重。有些具有来自 UCAallkeys.txt文件的显式权重。其他根据此算法计算权重:aaaa= base + (code >> 15); bbbb= (code & 0x7FFF) | 0x8000;
“按字符的代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅在utf16_bin中出现,因为存在代理。
假设utf16_bin(utf16的二进制校对)是一种“逐字节”而不是“逐字符”进行二进制比较。如果是这样,那么utf16_bin中字符的顺序将与utf8mb4_bin中的顺序不同。例如,以下图表显示了两个罕见字符。第一个字符位于E000-FFFF范围内,因此大于代理但小于补充字符。第二个字符是一个补充字符。
Code point Character utf8mb4 utf16
---------- --------- ------- -----
0FF9D HALFWIDTH KATAKANA LETTER N EF BE 9D FF 9D
10384 UGARITIC LETTER DELTA F0 90 8E 84 D8 00 DF 84
图表中的两个字符按代码点值顺序排列,因为0xff9d < 0x10384。它们按utf8mb4值顺序排列,因为0xef < 0xf0。但如果我们使用逐字节比较,它们按utf16值顺序排列,因为0xff > 0xd8。
因此,MySQL 的utf16_bin校对不是“逐字节”的。它是“按代码点”。当 MySQL 在utf16中看到补充字符编码时,它会转换为字符的代码点值,然后进行比较。因此,utf8mb4_bin和utf16_bin具有相同的排序。这与 SQL:2008 标准对 UCS_BASIC 校对的要求一致:“UCS_BASIC 是一种校对,其排序完全由要排序的字符串中字符的 Unicode 标量值确定。它适用于 UCS 字符库。由于每个字符库都是 UCS 字符库的子集,因此 UCS_BASIC 校对可能适用于每个字符集。注 11:字符的 Unicode 标量值是将其代码点视为无符号整数。”
如果字符集是ucs2,比较是逐字节的,但ucs2字符串不应包含代理项。
其他信息
*xxx*_general_mysql500_ci校对保留了原始*xxx*_general_ci校对的 5.1.24 版本之前的排序,并允许升级用于在 MySQL 5.1.24 之前创建的表(Bug#27877)。
12.10.2 西欧字符集
西欧字符集涵盖大多数西欧语言,如法语、西班牙语、加泰罗尼亚语、巴斯克语、葡萄牙语、意大利语、阿尔巴尼亚语、荷兰语、德语、丹麦语、瑞典语、挪威语、芬兰语、法罗语、冰岛语、爱尔兰语、苏格兰语和英语。
-
ascii(美国 ASCII)排序规则:-
ascii_bin -
ascii_general_ci(默认)
-
-
cp850(DOS 西欧)排序规则:-
cp850_bin -
cp850_general_ci(默认)
-
-
dec8(DEC 西欧)排序规则:-
dec8_bin -
dec8_swedish_ci(默认)
MySQL 8.0.28 中已弃用
dec字符集;预计在后续 MySQL 版本中将删除对其的支持。 -
-
hp8(HP 西欧)排序规则:-
hp8_bin -
hp8_english_ci(默认)
MySQL 8.0.28 中已弃用
hp8字符集;预计在后续 MySQL 版本中将删除对其的支持。 -
-
latin1(cp1252 西欧)排序规则:-
latin1_bin -
latin1_danish_ci -
latin1_general_ci -
latin1_general_cs -
latin1_german1_ci -
latin1_german2_ci -
latin1_spanish_ci -
latin1_swedish_ci(默认)
MySQL 的
latin1与 Windows 的cp1252字符集相同。这意味着它与官方的ISO 8859-1或 IANA(互联网编号分配机构)latin1相同,只是 IANAlatin1将0x80到0x9f之间的代码点视为“未定义”,而cp1252,因此 MySQL 的latin1,为这些位置分配了字符。例如,0x80是欧元符号。对于cp1252中的“未定义”条目,MySQL 将0x81转换为 Unicode0x0081,0x8d转换为0x008d,0x8f转换为0x008f,0x90转换为0x0090,0x9d转换为0x009d。latin1_swedish_ci排序规则是 MySQL 大多数客户可能使用的默认排序规则。尽管经常说它基于瑞典/芬兰排序规则,但也有瑞典人和芬兰人不同意这种说法。latin1_german1_ci和latin1_german2_ci排序规则基于 DIN-1 和 DIN-2 标准,其中 DIN 代表德国标准化学会(ANSI 的德国等效)。DIN-1 称为“字典排序”,DIN-2 称为“电话簿排序”。有关此在比较或进行搜索时的影响的示例,请参见第 12.8.6 节,“排序效果示例”。-
latin1_german1_ci��字典)规则:Ä = A Ö = O Ü = U ß = s -
latin1_german2_ci(电话簿)规则:Ä = AE Ö = OE Ü = UE ß = ss
在
latin1_spanish_ci排序规则中,ñ(n-tilde)是n和o之间的一个独立字母。 -
-
macroman(Mac 西欧)排序规则:-
macroman_bin -
macroman_general_ci(默认)
macroroman在 MySQL 8.0.28 中已弃用;预计在后续 MySQL 版本中将删除对其的支持。 -
-
swe7(7 位瑞典语)排序规则:-
swe7_bin -
swe7_swedish_ci(默认)
-
12.10.3 中欧字符集
MySQL 为捷克共和国、斯洛伐克、匈牙利、罗马尼亚、斯洛文尼亚、克罗地亚、波兰和塞尔维亚(拉丁文)使用的字符集提供了一些支持。
-
cp1250(Windows 中欧)排序规则:-
cp1250_bin -
cp1250_croatian_ci -
cp1250_czech_cs -
cp1250_general_ci(默认) -
cp1250_polish_ci
-
-
cp852(DOS 中欧)排序规则:-
cp852_bin -
cp852_general_ci(默认)
-
-
keybcs2(DOS Kamenicky Czech-Slovak)排序规则:-
keybcs2_bin -
keybcs2_general_ci(默认)
-
-
latin2(ISO 8859-2 中欧)排序规则:-
latin2_bin -
latin2_croatian_ci -
latin2_czech_cs -
latin2_general_ci(默认) -
latin2_hungarian_ci
-
-
macce(Mac 中欧)排序规则:-
macce_bin -
macce_general_ci(默认)
macce在 MySQL 8.0.28 中已被弃用;预计在随后的 MySQL 版本中将不再支持它。 -
12.10.4 南欧和中东字符集
MySQL 支持的南欧和中东字符集包括亚美尼亚语、阿拉伯语、格鲁吉亚语、希腊语、希伯来语和土耳其语。
-
armscii8(ARMSCII-8 亚美尼亚语)排序规则:-
armscii8_bin -
armscii8_general_ci(默认)
-
-
cp1256(Windows 阿拉伯语)排序规则:-
cp1256_bin -
cp1256_general_ci(默认)
-
-
geostd8(GEOSTD8 格鲁吉亚语)排序规则:-
geostd8_bin -
geostd8_general_ci(默认)
-
-
greek(ISO 8859-7 希腊语)排序规则:-
greek_bin -
greek_general_ci(默认)
-
-
hebrew(ISO 8859-8 希伯来语)排序规则:-
hebrew_bin -
hebrew_general_ci(默认)
-
-
latin5(ISO 8859-9 土耳其语)排序规则:-
latin5_bin -
latin5_turkish_ci(默认)
-
12.10.5 波罗的海字符集
波罗的海字符集涵盖爱沙尼亚语、拉脱维亚语和立陶宛语。
-
cp1257(Windows 波罗的海)排序规则:-
cp1257_bin -
cp1257_general_ci(默认) -
cp1257_lithuanian_ci
-
-
latin7(ISO 8859-13 波罗的海)排序规则:-
latin7_bin -
latin7_estonian_cs -
latin7_general_ci(默认) -
latin7_general_cs
-
12.10.6 西里尔字母字符集
原文:
dev.mysql.com/doc/refman/8.0/en/charset-cyrillic-sets.html
西里尔字母字符集和排序规则适用于白俄罗斯语、保加利亚语、俄罗斯语、乌克兰语和塞尔维亚语(西里尔字母)。
-
cp1251(Windows 西里尔字母)排序规则:-
cp1251_bin -
cp1251_bulgarian_ci -
cp1251_general_ci(默认) -
cp1251_general_cs -
cp1251_ukrainian_ci
-
-
cp866(DOS 俄语)排序规则:-
cp866_bin -
cp866_general_ci(默认)
-
-
koi8r(KOI8-R Relcom 俄语)排序规则:-
koi8r_bin -
koi8r_general_ci(默认)
-
-
koi8u(KOI8-U 乌克兰语)排序规则:-
koi8u_bin -
koi8u_general_ci(默认)
-
12.10.7 亚洲字符集
12.10.7.1 cp932 字符集
12.10.7.2 gb18030 字符集
我们支持的亚洲字符集包括中文、日文、韩文和泰文。这些可能会比较复杂。例如,中文字符集必须允许成千上万种不同的字符。有关 cp932 和 sjis 字符集的更多信息,请参见第 12.10.7.1 节,“cp932 字符集”。有关支持中国国家标准 GB 18030 字符集的更多信息,请参见第 12.10.7.2 节,“gb18030 字符集”。
有关 MySQL 中支持亚洲字符集的一些常见问题和问题的答案,请参见第 A.11 节,“MySQL 8.0 FAQ: MySQL 中文、日文和韩文字符集”。
-
big5(Big5 繁体中文) 校对规则:-
big5_bin -
big5_chinese_ci(默认)
-
-
cp932(Windows 日文 SJIS) 校对规则:-
cp932_bin -
cp932_japanese_ci(默认)
-
-
eucjpms(Windows 日文 UJIS) 校对规则:-
eucjpms_bin -
eucjpms_japanese_ci(默认)
-
-
euckr(EUC-KR 韩文) 校对规则:-
euckr_bin -
euckr_korean_ci(默认)
-
-
gb2312(GB2312 简体中文) 校对规则:-
gb2312_bin -
gb2312_chinese_ci(默认)
-
-
gbk(GBK 简体中文) 校对规则:-
gbk_bin -
gbk_chinese_ci(默认)
-
-
gb18030(中国国家标准 GB18030) 校对规则:-
gb18030_bin -
gb18030_chinese_ci(默认) -
gb18030_unicode_520_ci
-
-
sjis(Shift-JIS 日文) 校对规则:-
sjis_bin -
sjis_japanese_ci(默认)
-
-
tis620(TIS620 泰文) 校对规则:-
tis620_bin -
tis620_thai_ci(默认)
-
-
ujis(EUC-JP 日文) 校对规则:-
ujis_bin -
ujis_japanese_ci(默认)
-
big5_chinese_ci 校对规则按笔画数排序。
12.10.7.1 cp932字符集
为什么需要cp932?
在 MySQL 中,sjis字符集对应于 IANA 定义的Shift_JIS字符集,支持 JIS X0201 和 JIS X0208 字符。(参见www.iana.org/assignments/character-sets。)
然而,“SHIFT JIS”作为一个描述性术语的含义变得非常模糊,通常包括各种供应商定义的Shift_JIS扩展。
例如,在日本 Windows 环境中使用的“SHIFT JIS”是Shift_JIS的微软扩展,其确切名称为Microsoft Windows Codepage : 932或cp932。除了Shift_JIS支持的字符外,cp932还支持扩展字符,如 NEC 特殊字符、NEC 选定-IBM 扩展字符和 IBM 选定字符。
许多日本用户在使用这些扩展字符时遇到问题。这些问题源于以下因素:
-
MySQL 会自动转换字符集。
-
字符集使用 Unicode(
ucs2)进行转换。 -
sjis字符集不支持这些扩展字符的转换。 -
从所谓的“SHIFT JIS”到 Unicode 有几种转换规则,根据转换规则的不同,一些字符转换为 Unicode 的方式也不同。MySQL 仅支持其中一种规则(稍后描述)。
MySQL 的cp932字符集旨在解决这些问题。
因为 MySQL 支持字符集转换,所以将 IANA 的Shift_JIS和cp932分开成两个不同的字符集非常重要,因为它们提供不同的转换规则。
cp932与sjis有何不同?
cp932字符集与sjis有以下不同:
-
cp932支持 NEC 特殊字符、NEC 选定-IBM 扩展字符和 IBM 选定字符。 -
一些
cp932字符有两个不同的代码点,两者都转换为相同的 Unicode 代码点。在从 Unicode 转换回cp932时,必须选择其中一个代码点。对于这种“往返转换”,使用微软推荐的规则。(参见support.microsoft.com/kb/170559/EN-US/。)转换规则如下:
-
如果字符同时在 JIS X 0208 和 NEC 特殊字符中,则使用 JIS X 0208 的代码点。
-
如果字符同时在 NEC 特殊字符和 IBM 选定字符中,则使用 NEC 特殊字符的代码点。
-
如果字符同时在 IBM 选定字符和 NEC 选定-IBM 扩展字符中,则使用 IBM 扩展字符的代码点。
msdn.microsoft.com/en-us/goglobal/cc305152.aspx上显示的表提供了关于cp932字符的 Unicode 值的信息。对于cp932表中带有四位数值下字符的条目,该数字代表相应的 Unicode(ucs2)编码。对于带有下划线的两位数值下字符的条目,存在以这两位数值开头的一系列cp932字符值。点击这样的表条目会带您到一个页面,显示以这些数字开头的每个cp932字符的 Unicode 值。以下链接非常重要。它们对应以下字符集的编码:
-
NEC 特殊字符(主字节
0x87):https://msdn.microsoft.com/en-us/goglobal/gg674964 -
NEC 选定—IBM 扩展字符(主字节
0xED和0xEE):https://msdn.microsoft.com/en-us/goglobal/gg671837 https://msdn.microsoft.com/en-us/goglobal/gg671838 -
IBM 选定字符(主字节
0xFA、0xFB、0xFC):https://msdn.microsoft.com/en-us/goglobal/gg671839 https://msdn.microsoft.com/en-us/goglobal/gg671840 https://msdn.microsoft.com/en-us/goglobal/gg671841
-
-
cp932支持与eucjpms结合使用的用户定义字符的转换,并解决了sjis/ujis转换的问题。详情请参考www.sljfaq.org/afaq/encodings.html。
对于一些字符,sjis 和 cp932 的 ucs2 转换是不同的。以下表格展示了这些差异。
转换为 ucs2:
sjis/cp932 值 | sjis -> ucs2 转换 | cp932 -> ucs2 转换 |
|---|---|---|
| 5C | 005C | 005C |
| 7E | 007E | 007E |
| 815C | 2015 | 2015 |
| 815F | 005C | FF3C |
| 8160 | 301C | FF5E |
| 8161 | 2016 | 2225 |
| 817C | 2212 | FF0D |
| 8191 | 00A2 | FFE0 |
| 8192 | 00A3 | FFE1 |
| 81CA | 00AC | FFE2 |
sjis/cp932 值 | sjis -> ucs2 转换 | cp932 -> ucs2 转换 |
从 ucs2 转换:
ucs2 值 | ucs2 -> sjis 转换 | ucs2 -> cp932 转换 |
|---|---|---|
| 005C | 815F | 5C |
| 007E | 7E | 7E |
| 00A2 | 8191 | 3F |
| 00A3 | 8192 | 3F |
| 00AC | 81CA | 3F |
| 2015 | 815C | 815C |
| 2016 | 8161 | 3F |
| 2212 | 817C | 3F |
| 2225 | 3F | 8161 |
| 301C | 8160 | 3F |
| FF0D | 3F | 817C |
| FF3C | 3F | 815F |
| FF5E | 3F | 8160 |
| FFE0 | 3F | 8191 |
| FFE1 | 3F | 8192 |
| FFE2 | 3F | 81CA |
ucs2 值 | ucs2 -> sjis 转换 | ucs2 -> cp932 转换 |
任何日文字符集的用户都应该注意使用 --character-set-client-handshake(或 --skip-character-set-client-handshake)会产生重要影响。请参阅 7.1.7 “服务器命令选项”。
12.10.7.2 gb18030 字符集
在 MySQL 中,gb18030 字符集对应于“中华人民共和国国家标准 GB 18030-2005:信息技术-中文编码字符集”,这是中华人民共和国的官方字符集。
MySQL gb18030 字符集的特点
-
支持 GB 18030-2005 标准定义的所有代码点。范围内未分配的代码点(GB+8431A439,GB+90308130)和(GB+E3329A36,GB+EF39EF39)被视为 '
?'(0x3F)。未分配代码点的转换返回 '?'。 -
支持对所有 GB18030 代码点进行 UPPER 和 LOWER 转换。还支持 Unicode 定义的大小写折叠(基于
CaseFolding-6.3.0.txt)。 -
支持将数据转换为其他字符集和从其他字符集转换。
-
支持 SQL 语句,如
SET NAMES。 -
支持比较
gb18030字符串,以及gb18030字符串与其他字符集的字符串之间的比较。如果字符串具有不同的字符集,则进行转换。还支持包含或忽略尾随空格的比较。 -
Unicode 中的专用使用区域(U+E000,U+F8FF)映射到
gb18030。 -
Unicode(U+D800,U+DFFF)和 GB18030 之间没有映射。尝试转换此范围内的代码点将返回 '
?'。 -
如果输入序列非法,则返回错误或警告。如果在
CONVERT()中使用非法序列,则返回错误。否则,返回警告。 -
为了与
utf8mb3和utf8mb4保持一致,不支持对连字使用 UPPER。 -
使用
gb18030_unicode_520_ci排序时,搜索连字也会匹配大写连字。 -
如果一个字符有多个大写字符,则选择的大写字符是其小写字符本身。
-
最小多字节长度为 1,最大为 4。字符集使用前 1 或 2 个字节确定序列的长度。
支持的排序规则
-
gb18030_bin: 二进制排序。 -
gb18030_chinese_ci: 默认排序规则,支持拼音。非中文字符的排序基于原始排序键的顺序。如果UPPER(ch)存在,则原始排序键为GB(UPPER(ch))。否则,原始排序键为GB(ch)。中文字符根据 Unicode 公共区域数据存储库(CLDR 24)中定义的拼音排序进行排序。非中文字符在中文字符之前排序,除了GB+FE39FE39,这是代码点最大值。 -
gb18030_unicode_520_ci: Unicode 排序。如果需要确保连字正确排序,请使用此排序。