优先选text的场景是字段超长且不常参与where/order by;否则一律用varchar——因varchar行内存储受限,而text虽存于行外但带来i/o增加、索引退化等隐性成本。

超过 255 字符且不常参与 WHERE/ORDER BY 的长文本,优先选 TEXT;否则一律用 VARCHAR——别被“最大长度 65535”误导,VARCHAR 在行内存储有硬性限制,而 TEXT 的代价是额外 I/O 和索引能力退化。
什么时候必须用 TEXT?
不是“能存多”就该用 TEXT,而是当字段内容稳定超长、且基本不参与高频过滤或排序时才值得切换。典型场景包括:文章正文、用户反馈日志、API 响应快照。
-
TEXT系列(TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT)实际存储在行外,主记录只留 20 字节指针,避免单行膨胀导致页分裂 - 若字段平均长度 > 500 字符,且写入后极少更新,
TEXT能显著降低 InnoDB 行迁移频率 - 注意:
TEXT列无法设默认值(MySQL 8.0.19+ 仅对TINYTEXT/TEXT放宽,但不推荐依赖)
为什么 VARCHAR(65535) 很少能真正用满?
MySQL 单行总大小上限为 65535 字节(不含 BLOB/TEXT),而这一限制包含所有列的开销:长度标识、NULL 标志位、行头信息。真实可用空间远小于理论值。
- 一个
VARCHAR字段在 utf8mb4 下,每字符最多占 4 字节;VARCHAR(65535)理论最大需 262140 字节,根本不可能存进一行 - 实践中,只要表里还有其他字段(哪怕只是
INT+NOT NULL),VARCHAR能安全使用的上限通常 ≤ 65500 字节,且需预留至少 2 字节长度标识 - 更关键的是:InnoDB 行格式(如
Dynamic)会在字段 > 255 字节时自动启用溢出页——此时它和TEXT的物理存储差异已不大,但VARCHAR仍要承担索引前缀长度限制(默认 767 字节)
TEXT 的隐性成本比你想象中高
它不只是“存得下”,而是把性能瓶颈从磁盘空间转移到了 I/O 和内存管理上。
- 含
TEXT列的查询,即使只SELECT id,也可能触发全行读取(除非使用覆盖索引且明确排除该列) -
ORDER BY或GROUP BY涉及TEXT列时,MySQL 强制走磁盘临时表,tmp_table_size和max_heap_table_size设置再大也没用 - 索引只能建前缀,例如
INDEX(content(255));但若业务常按后半段内容搜索(如日志末尾错误码),这个索引基本失效 - 备份与复制压力更大:
TEXT内容不压缩传输,binlog 中以完整值记录,增大网络带宽消耗
一个够用的决策流程
别靠感觉,按这四步判断:
- 字段是否经常出现在
WHERE、JOIN、ORDER BY条件中?→ 是 → 必须VARCHAR(哪怕截断到 500) - 平均长度是否稳定 ≥ 1000 字符?且更新频次 MEDIUMTEXT
- 是否需要全文检索?→ 是 →
TEXT+FULLTEXT索引是唯一选择(VARCHAR不支持) - 是否要对该列设默认值或参与生成列计算?→ 是 → 只能用
VARCHAR(TEXT在 MySQL 8.0+ 仍不支持生成列引用)
真正棘手的从来不是“能不能存”,而是“查得动、排得动、备得动”。TEXT 是把双刃剑,挥出去之前,先确认你握得住柄。











