如何用SQL的LENGTH和CHAR_LENGTH函数区分并获取字符串字节长度的不同之处?
- 内容介绍
- 文章标签
- 相关推荐
本文共计895个文字,预计阅读时间需要4分钟。
在MySQL中,`LENGTH()` 和 `CHAR_LENGTH()` 都可以用来计算字符串长度,但它们的意义有所不同。`LENGTH()` 返回的是字符串的物理字节长度,而 `CHAR_LENGTH()` 返回的是字符的个数。
如果你关心的是这个字段实际占多少存储空间或是否超出VARBINARY限制,你应该使用 `LENGTH()`,因为它的值包括了所有字符的编码字节。
如果你只关心有几个汉字/字母,应该使用 `CHAR_LENGTH()`,因为它不考虑字符编码的长度差异。
简而言之:
根本原因在于 MySQL 的字符集处理方式:UTF8MB4 下,一个汉字占 3 或 4 字节,而 LENGTH() 按字节计数,CHAR_LENGTH() 按 Unicode 字符计数(无论多长)。
中文、emoji 场景下 LENGTH 明显大于 CHAR_LENGTH
执行这条语句就能直观看到差异:
SELECT '你好?' AS str, LENGTH('你好?') AS byte_len, CHAR_LENGTH('你好?') AS char_len;
结果通常是:byte_len = 10(“你好”各 3 字节 + ? 占 4 字节),char_len = 3(两个汉字 + 一个 emoji 算一个字符)。
- 若字段定义为
VARCHAR(10),存得下这个字符串(字符数没超) - 但若底层是
VARBINARY(10)或做 HTTP header 截断逻辑,10 字节根本装不下 —— 这时只看CHAR_LENGTH()就会出错 - 某些旧系统用
LENGTH()做密码哈希前校验长度,UTF8MB4 下可能误判超长
PostgreSQL 和 SQL Server 不叫 CHAR_LENGTH
MySQL 的 CHAR_LENGTH() 在 PostgreSQL 里叫 CHAR_LENGTH()(同名),但 SQL Server 只有 LEN() —— 它的行为等价于 MySQL 的 CHAR_LENGTH(),不提供原生字节长度函数。SQL Server 要算字节长度得绕一下:
SELECT DATALENGTH(N'你好?'); -- 返回 10,注意必须用 N'' 前缀表示 Unicode
Oracle 用 LENGTHB() 表示字节长度,LENGTH() 默认是字符长度(和 MySQL 相反)。
- 跨数据库写迁移脚本时,别直接复制
LENGTH()—— 先确认目标库的默认语义 - MySQL 5.7+ 默认字符集是 utf8mb4,
LENGTH()的结果比老版本更“膨胀”,升级后要重测长度校验逻辑
WHERE 条件里混用 LENGTH 和 CHAR_LENGTH 可能导致索引失效
如果在 WHERE 子句里对字段套 LENGTH(col) > 10,即使 col 有索引,MySQL 通常也无法走索引(属于对列做函数运算)。而 CHAR_LENGTH(col) > 10 同样如此。
- 真要按长度过滤且需性能,建议加生成列:
ALTER TABLE t ADD COLUMN byte_len INT AS (LENGTH(str_col)) STORED,再给它建索引 - 或者业务层提前计算好长度存到单独字段,避免每次查都算
- 特别注意:JSON 字段用
LENGTH(json_col)返回的是整个 JSON 文本的字节数,不是里面某个 key 的值长度
实际用哪个,取决于你到底在约束什么:是磁盘空间、网络传输、协议限制(字节),还是用户感知、显示宽度、业务规则(字符)。两者差的那几个字节,常常就是线上截断、乱码、越界报错的源头。
本文共计895个文字,预计阅读时间需要4分钟。
在MySQL中,`LENGTH()` 和 `CHAR_LENGTH()` 都可以用来计算字符串长度,但它们的意义有所不同。`LENGTH()` 返回的是字符串的物理字节长度,而 `CHAR_LENGTH()` 返回的是字符的个数。
如果你关心的是这个字段实际占多少存储空间或是否超出VARBINARY限制,你应该使用 `LENGTH()`,因为它的值包括了所有字符的编码字节。
如果你只关心有几个汉字/字母,应该使用 `CHAR_LENGTH()`,因为它不考虑字符编码的长度差异。
简而言之:
根本原因在于 MySQL 的字符集处理方式:UTF8MB4 下,一个汉字占 3 或 4 字节,而 LENGTH() 按字节计数,CHAR_LENGTH() 按 Unicode 字符计数(无论多长)。
中文、emoji 场景下 LENGTH 明显大于 CHAR_LENGTH
执行这条语句就能直观看到差异:
SELECT '你好?' AS str, LENGTH('你好?') AS byte_len, CHAR_LENGTH('你好?') AS char_len;
结果通常是:byte_len = 10(“你好”各 3 字节 + ? 占 4 字节),char_len = 3(两个汉字 + 一个 emoji 算一个字符)。
- 若字段定义为
VARCHAR(10),存得下这个字符串(字符数没超) - 但若底层是
VARBINARY(10)或做 HTTP header 截断逻辑,10 字节根本装不下 —— 这时只看CHAR_LENGTH()就会出错 - 某些旧系统用
LENGTH()做密码哈希前校验长度,UTF8MB4 下可能误判超长
PostgreSQL 和 SQL Server 不叫 CHAR_LENGTH
MySQL 的 CHAR_LENGTH() 在 PostgreSQL 里叫 CHAR_LENGTH()(同名),但 SQL Server 只有 LEN() —— 它的行为等价于 MySQL 的 CHAR_LENGTH(),不提供原生字节长度函数。SQL Server 要算字节长度得绕一下:
SELECT DATALENGTH(N'你好?'); -- 返回 10,注意必须用 N'' 前缀表示 Unicode
Oracle 用 LENGTHB() 表示字节长度,LENGTH() 默认是字符长度(和 MySQL 相反)。
- 跨数据库写迁移脚本时,别直接复制
LENGTH()—— 先确认目标库的默认语义 - MySQL 5.7+ 默认字符集是 utf8mb4,
LENGTH()的结果比老版本更“膨胀”,升级后要重测长度校验逻辑
WHERE 条件里混用 LENGTH 和 CHAR_LENGTH 可能导致索引失效
如果在 WHERE 子句里对字段套 LENGTH(col) > 10,即使 col 有索引,MySQL 通常也无法走索引(属于对列做函数运算)。而 CHAR_LENGTH(col) > 10 同样如此。
- 真要按长度过滤且需性能,建议加生成列:
ALTER TABLE t ADD COLUMN byte_len INT AS (LENGTH(str_col)) STORED,再给它建索引 - 或者业务层提前计算好长度存到单独字段,避免每次查都算
- 特别注意:JSON 字段用
LENGTH(json_col)返回的是整个 JSON 文本的字节数,不是里面某个 key 的值长度
实际用哪个,取决于你到底在约束什么:是磁盘空间、网络传输、协议限制(字节),还是用户感知、显示宽度、业务规则(字符)。两者差的那几个字节,常常就是线上截断、乱码、越界报错的源头。

