本节描述了二进制字符串的 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 字符集”。
二进制排序法与 _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 表来确定排序的 pad 属性。
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 |
+------+------------------------+--------+----------------------+