用四种不同的文本测utf8mb4真实的字节占用,再往老式utf8(mb3)列塞emoji,看它在严格和宽松模式下真实的两种不同下场。
代码CREATE TABLE charlen_test (id INT PRIMARY KEY AUTO_INCREMENT, txt VARCHAR(50)) CHARACTER SET utf8mb4; INSERT INTO charlen_test (txt) VALUES ('hello'), ('你好世界'), ('😀🎉🚀'), ('café'); SELECT txt, CHAR_LENGTH(txt), LENGTH(txt) FROM charlen_test;
txt 字符数 字节数 平均每字符字节数 hello 5 5 1.00 你好世界 4 12 3.00 😀🎉🚀 3 12 4.00 café 4 5 1.25
utf8mb4真实是变长编码,每个字符占用的字节数从1到4不等:纯ASCII字符(hello)真实1字节1个;常见中文字符(你好世界)真实是3字节1个;emoji(😀🎉🚀)真实需要满打满算的4字节,这正是"mb4"里"4"的由来;café里的é是带重音符号的拉丁字母,真实占2字节,其余3个ASCII字符各占1字节,平均下来1.25字节/字符。
严格模式(默认sql_mode):
INSERT INTO charlen_old (txt) VALUES ('😀🎉🚀');
→ ERROR 1366: Incorrect string value: '\xF0\x9F\x98\x80\xF0\x9F...' ← 真实直接拒绝插入
宽松模式(sql_mode=''):
INSERT INTO charlen_old (txt) VALUES ('😀🎉🚀');
→ 真实插入"成功",但查出来变成了:???
LENGTH(txt) = 3 ← 三个问号,原始数据真实已经丢了每一步都是本文上面用真实查询跑出来的原始结果。
CHAR_LENGTH()(字符数) vs LENGTH()(字节数)