LENGTH()返回字节数,CHAR_LENGTH()返回字符数;UTF8MB4下中文、emoji等多字节字符会使LENGTH()大于CHAR_LENGTH(),前者反映真实存储开销。

LENGTH 和 CHAR_LENGTH 的区别到底在哪
MySQL 中 LENGTH() 返回的是字节长度,CHAR_LENGTH() 返回的是字符个数。对 ASCII 字符(如英文、数字、标点)两者结果一致;但对 UTF8MB4 编码下的中文、emoji、某些生僻字,一个字符可能占 2~4 字节,这时 LENGTH() 就会大于 CHAR_LENGTH()。
查字段实际存储开销,关键看字节——因为磁盘和内存分配都按字节算,所以 LENGTH() 更贴近真实空间占用。
- UTF8MB4 下,普通汉字通常占 3 字节,部分扩展区汉字或 emoji 占 4 字节
-
CHAR(10)定义的是“最多存 10 个字符”,但实际存储 “你好” 时,LENGTH('你好')是 6,不是 2 - 如果字段定义为
VARCHAR(255)且只存了 1 个 emoji(如 ?),LENGTH()返回 4,而非 1
怎么查某张表所有非空字段的平均字节长度
不能直接对整个表用 LENGTH() 聚合,必须逐行计算再平均。典型写法是结合 AVG() 和 LENGTH(),并注意过滤 NULL 和空字符串。
SELECT AVG(LENGTH(name)) AS avg_name_bytes, AVG(LENGTH(content)) AS avg_content_bytes FROM users WHERE name IS NOT NULL AND name != '';
如果要查多个字段且不想写一堆 AVG(LENGTH()),可封装成临时查询或视图;但别在大表上直接跑——LENGTH() 是逐行函数,无索引加速,全表扫描开销明显。
- 对 TEXT 或 LONGTEXT 字段慎用,尤其当存在超长内容时,
LENGTH()计算本身就会变慢 - 如果字段有前缀索引(如
INDEX(content(100))),不代表它只存了 100 字节,LENGTH(content)仍返回完整内容的字节数 - 想看「当前数据下各字段最大字节占用」,把
AVG换成MAX(LENGTH())
为什么 SELECT LENGTH(col) 总返回 NULL
最常见原因是字段值本身为 NULL。LENGTH(NULL) 必然返回 NULL,这不是函数异常,而是 MySQL 的三值逻辑行为。
- 检查是否漏加
WHERE col IS NOT NULL - 确认字段没被意外设为允许 NULL 且大量为空(比如迁移后未补默认值)
- 某些 ORM 或中间件会把空字符串自动转成 NULL,导致表里看着是空但实为 NULL
- 若字段是
TEXT类型且启用了严格模式,超长截断也可能触发隐式 NULL 化(较少见,需查sql_mode)
CHAR、VARCHAR、TEXT 字段的实际空间怎么估算
仅靠 LENGTH() 还不够——MySQL 存储引擎会在值之外额外加 1~2 字节记录长度(VARCHAR 用 1 字节存 ≤255 字节长度,>255 则用 2 字节;TEXT 类型另有指针开销)。另外,行格式(如 ROW_FORMAT=COMPACT)也影响 NULL 值的存储标记位。
简单估算公式:实际占用 ≈ LENGTH(col) + 长度头字节 +(若为 NULL 且列允许 NULL,则 +1 位标记)。但精确值得看 INFORMATION_SCHEMA.INNODB_SYS_COLUMNS 和表统计信息,日常诊断用 LENGTH() 已足够定位“哪个字段吃空间最多”。
- CHAR(10) 存 'a':
LENGTH()返回 1,但磁盘上仍占 10 字节(填充空格),LENGTH()不体现这部分 - 想验证填充行为,用
HEX(col)看末尾是否有20(空格 ASCII) - 真正省空间,优先考虑把冗余
CHAR改成VARCHAR,再用LENGTH()观察真实分布
实际调优时,LENGTH() 是起点,不是终点。它能快速暴露“字段存了远超预期的二进制体积”,但具体到页分裂、缓冲池压力、备份大小,还得结合 SHOW TABLE STATUS 和 information_schema.TABLES 里的 Data_length 对照看。


















