mysql中length()返回字节数而非字符数,如'你好'结果为8;char_length()才返回字符数,值为2,推荐业务中默认使用。

LENGTH函数返回字节数,不是字符数
在MySQL中,LENGTH() 返回的是字符串占用的字节数,不是“看起来有几个字”的字符个数。比如中文在UTF8mb4编码下通常占4字节,LENGTH('你好') 结果是8,而不是2。这在做字段截断、长度校验或与前端传入字符数对比时容易出错——前端JS的str.length数的是Unicode字符,后端用LENGTH()一算就对不上。
常见错误现象:WHERE LENGTH(name) > 10 本意是限制“超10个汉字”,结果实际拦住了“3个emoji(每个4字节)+1个汉字”,因为总字节数已超10。
- 适用于:判断存储开销、配合
LEFT()/SUBSTRING()按字节截取(极少见) - 不适用于:用户名/标题等需按“人眼可见字符数”校验的场景
- 注意:结果受连接字符集影响,
SET NAMES utf8mb4后才稳定反映真实字节数
CHAR_LENGTH函数才真正返回字符个数
CHAR_LENGTH()(MySQL里也支持别名CHARACTER_LENGTH())才是你日常需要的“字符串有几个字符”。它按Unicode码点计数,CHAR_LENGTH('??a') 返回2(一个ZJW emoji + 一个英文字符),CHAR_LENGTH('你好') 返回2,和JavaScript、Python的len()行为一致。
使用场景集中在业务逻辑层:用户名长度限制、短信内容字符统计、JSON字段内字符串校验等。
- 推荐默认使用
CHAR_LENGTH(),除非明确要按字节操作 - PostgreSQL里只有
LENGTH(),但它的行为等价于MySQL的CHAR_LENGTH()——这点容易跨数据库迁移时踩坑 - SQL Server用
LEN(),也是按字符数,但会自动忽略末尾空格;MySQL的CHAR_LENGTH()则保留空格
不同字符集下LENGTH结果差异极大
同一个字符串,在latin1、utf8、utf8mb4下,LENGTH()结果可能完全不同。比如字符'€':latin1中占1字节,utf8中占3字节,utf8mb4中还是3字节;而emoji'?'在utf8mb4中占4字节,在utf8(非mb4)中甚至无法存入。
这意味着:如果表字段是VARCHAR(255) CHARACTER SET latin1,用LENGTH()查到的最大值是255;但改成utf8mb4后,同样定义下最多只能存63个4字节字符(63×4=252),LENGTH()可能达到252,但CHAR_LENGTH()仍是63。
- 建表时若依赖
LENGTH()做约束,必须锁死字符集,否则迁移后逻辑失效 - 用
SHOW CREATE TABLE确认字段实际字符集,别只看建表语句里的默认值 - 备份还原、主从同步时字符集不一致,
LENGTH()查询结果可能突变
ORDER BY + LENGTH组合排序容易误判显示长度
写ORDER BY LENGTH(title) DESC看似按“标题长短”排序,实则按字节数排。结果可能是:10个英文字母(10字节)排在2个中文(8字节)前面,但视觉上后者更长。用户看到“abc...”排在“你好”上面,会觉得排序错乱。
这不是bug,是设计使然。但业务上几乎没人真想按字节排标题长度。
- 改用
ORDER BY CHAR_LENGTH(title) DESC更符合直觉 - 如需兼顾中英文混排的“视觉宽度”,得上应用层处理(如用monospace字体宽度估算),SQL层做不到
- 索引无法加速
CHAR_LENGTH()排序,大数据量时要考虑加生成列+索引










