业务校验必须用char_length(),因length()按字节数计算,utf8mb4下汉字占3字节、emoji占4字节,导致长度限制失效;char_length()按unicode码点计数,与前端语言一致,是日常唯一应使用的函数。

业务校验必须用 CHAR_LENGTH(),查字节开销才用 LENGTH() —— 混用会导致长度限制失效、前端后端对不上、emoji 被误放行或误拦截。
为什么 LENGTH() 返回的不是“看起来有几个字”
LENGTH() 算的是字节数,完全取决于当前连接和字段的字符集。utf8mb4 下一个汉字占 3 字节(如 '你'),emoji 占 4 字节(如 '?'),所以 LENGTH('你好') 返回 6,LENGTH('?') 返回 4。而前端 JavaScript 的 str.length、Python 的 len() 都是按 Unicode 码点计数,值为 2 和 1。
常见错误现象:WHERE LENGTH(name) > 10 本意是拦住“超 10 个字符”,结果却放过 3 个 emoji + 1 个字母(总字节 4×3+1=13),却拦下 4 个汉字(4×3=12)——人眼和逻辑全对不上。
- 执行
SELECT @@character_set_client, @@collation_connection;确认当前连接字符集,它会影响LENGTH()对字面量的解析 - 建表时若字段定义为
VARCHAR(255) CHARACTER SET latin1,LENGTH()最大能到 255;但改成utf8mb4后,同样定义最多存 63 个 4 字节字符(63×4=252),LENGTH()就永远 ≤252 -
SHOW CREATE TABLE table_name查字段真实字符集,别信建表语句里没显式声明的“默认值”
什么时候非用 LENGTH() 不可
只有两类场景绕不开 LENGTH():
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 判断是否超出列的物理存储上限:比如字段是
VARCHAR(100) CHARACTER SET utf8mb4,你想确保插入不报错,就得用LENGTH()判断字节是否 ≤100 - 配合
SUBSTRING()或LEFT()按字节截断(极少见):比如日志系统要硬截断二进制安全字符串,也得按字节切,否则可能把一个多字节字符从中间劈开,存进去变成乱码
注意:LEFT(name, 100) 默认按字符截,但若想严格控字节,得确认连接字符集稳定,并理解它底层仍依赖当前 character_set_client 解析方式。
CHAR_LENGTH() 是日常唯一应使用的函数
CHAR_LENGTH()(等价于 CHARACTER_LENGTH())返回 Unicode 字符个数,和 JS、Python、Java 的字符串长度行为一致。用户昵称限 10 字、短信内容统计 70 字、JSON 字段内校验 key 长度,全部应该无条件用它。
- 它不受字符集切换影响:
CHAR_LENGTH('€')在latin1、utf8、utf8mb4下都是 1;CHAR_LENGTH('?')在所有支持 emoji 的字符集下都是 1 - 在触发器或存储过程中做截断,也要用
LEFT(col, 100)(它按字符截),而不是SUBSTR(col, 1, 100)(默认按字节,行为依赖character_set_client) - 主从同步或备份还原时,若主库用
utf8mb4、从库误配成utf8(非 mb4),LENGTH()查询结果会突变,而CHAR_LENGTH()不受影响
最易被忽略的一点:MySQL 的 LENGTH() 和 PostgreSQL 的 LENGTH() 行为完全不同——后者等价于 MySQL 的 CHAR_LENGTH()。跨数据库迁移时,直接照搬 SQL 很可能让长度校验逻辑彻底失效。










