最好使用utf8_bin
排序规则,因为即使在 UTF-8 中不可能,但在一般情况下,理论上可以(例如 UTF-16 发生的情况)用不同的编码表示相同的字符串,这二进制比较不会理解,但二进制排序规则会。如Unicode Character Sets下所述:
“按字符的代码值排序”和“按字符的二进制表示排序”之间存在差异,这种差异仅出现在utf16_bin
, 因为代理。
假设utf16_bin
( 的二进制排序规则utf16
)是“逐字节”而不是“逐字符”的二进制比较。如果是这样,则 in 中的字符顺序utf16_bin
将与 in 中的顺序不同utf8_bin
。例如,下图显示了两个稀有字符。第一个字符在 rangeE000-FFFF
中,因此它大于代理项但小于补充项。第二个字符是补充。
码点 字符 utf8 utf16
---------- --------- ---- -----
0FF9D 半宽片假名字母 N EF BE 9D FF 9D
10384 乌加里特字母 DELTA F0 90 8E 84 D8 00 DF 84
图表中的两个字符按代码点值排序,因为0xff9d
< 0x10384
。它们按utf8
值排序,因为0xef
< 0xf0
。utf16
但是如果我们使用逐字节比较,它们不是按值排序的,因为0xff
> 0xd8
。
所以 MySQL 的utf16_bin
排序规则不是“逐字节”的。它是“按代码点”。当 MySQL 在 中看到补充字符编码时utf16
,它会转换为字符的代码点值,然后进行比较。因此,utf8_bin
和utf16_bin
是相同的排序。这与 UCS_BASIC 排序规则的 SQL:2008 标准要求一致:“UCS_BASIC 是一种排序规则,其中排序完全由正在排序的字符串中字符的 Unicode 标量值确定。它适用于 UCS 字符库。由于每个字符库都是 UCS 库的子集,因此 UCS_BASIC 排序规则可能适用于每个字符集。注 11:字符的 Unicode 标量值是其代码点,被视为无符号整数。”</p>
因此,如果涉及这些列的比较总是区分大小写,则应将列的排序规则设置为utf8_bin
(这样即使您忘记在查询中另外指定,它们也将保持区分大小写);或者,如果只有特定查询区分大小写,则utf8_bin
可以使用COLLATE
关键字指定排序规则:
SELECT * FROM table WHERE id = 'iSZ6fX' COLLATE utf8_bin