MySQL CHAR_LENGTH(str)使用不同字符集引导符处理相同字符串字面量时输出不一致的原因探究
为什么
CHAR_LENGTH(_ucs2"Hello")返回3而不是5? 这是个很有意思的问题,核心原因出在UCS2字符集的编码规则以及MySQL处理非法编码输入的行为上,咱们一步步理清楚:
1. UCS2的核心特性
UCS2是一种固定长度的Unicode编码方式,它的规则很明确:
- 每个字符必须占用恰好2字节
- 仅支持Unicode基本多语言平面(BMP)的字符
- 要求输入的字节总数必须是偶数,否则无法正常解析完整字符
2. 拆解_ucs2"Hello"的实际处理过程
先看原字符串"Hello"的ASCII字节:H(0x48)、e(0x65)、l(0x6C)、l(0x6C)、o(0x6F),一共是5个字节——这是个奇数,不符合UCS2的偶数字节要求。
当你用_ucs2字符集引导符时,MySQL会尝试把这5个字节当作UCS2编码来解析,遇到字节数不足的情况,它会自动补一个空字节(0x00)凑成偶数,最终的字节序列变成:0x4865 0x6C6C 0x6F00。
现在按UCS2的2字节一组来解析:
0x4865→ 对应Unicode字符U+4865(一个CJK汉字)0x6C6C→ 对应Unicode字符U+6C6C(另一个CJK汉字)0x6F00→ 对应Unicode字符U+6F00(第三个CJK汉字)
这就变成了3个合法的UCS2字符,所以CHAR_LENGTH()自然返回3。
3. 对比utf8mb4和latin1的正常结果
- latin1:单字节编码,每个ASCII字符占1字节,5个字节对应5个独立字符,所以
CHAR_LENGTH返回5。 - utf8mb4:可变长度编码,ASCII字符仅占1字节,5个字节完美对应5个字符,结果符合预期。
验证方法
你可以用HEX()函数查看转换后的字节序列,确认补全行为:
SELECT HEX(_ucs2"Hello");
输出会是48656C6C6F00——最后多了一个00,正好凑成6字节(3组2字节)。
总结一下:CHAR_LENGTH()确实是按字符数统计,但前提是字符串在目标字符集下是合法编码。当原字符串的字节数不符合UCS2的偶数要求时,MySQL自动补全字节后解析出了3个UCS2字符,才出现了和预期不一致的结果。
内容的提问来源于stack exchange,提问作者Payel Senapati
相关产品推荐
相关产品推荐

