必须用text系列;但即使远低于64kb,只要字段常被读取、排序或参与where条件,varchar通常更稳——关键不在“能不能存”,而在“怎么查得快、写得省”。

超过 65,535 字节(约 64KB)必须用 TEXT 系列;但即使远低于这个值,只要字段常被读取、排序或参与 WHERE 条件,VARCHAR 通常更稳——关键不在“能不能存”,而在“怎么查得快、写得省”。
字段长度是否接近或超过 64KB?
这是硬分界线:TEXT 系列(TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT)是唯一能突破 VARCHAR 单字段 65,535 字节上限的方案。但要注意:
-
VARCHAR(65535)在 utf8mb4 下实际最多存约 16,383 个字符(每个字符占 4 字节),不是 65,535 个字符 - 整行总大小还受
innodb_page_size限制(默认 16KB),哪怕单字段没超,多字段叠加也可能触发行溢出 -
TEXT类型本身不计入行大小计算,所以它能“绕过”这个限制,但代价是外置存储
查询是否频繁读取该字段?
如果每次 SELECT * 或业务逻辑中都要取这个字段内容,VARCHAR 更友好:
-
VARCHAR内联存储,一次 I/O 就能读完整行(只要没溢出) -
TEXT字段在DYNAMIC行格式下,超过约 8000 字节就存到溢出页,读取需额外随机 I/O - 实测:同一条记录,
SELECT id, title FROM t比SELECT * FROM t快 2–4 倍,尤其当content是TEXT且体积较大时 - 若只查元数据(如列表页),建议显式排除
TEXT字段,避免拖慢整个结果集
是否需要对该字段建索引或用于 WHERE/ORDER BY?
这是最容易踩坑的地方:
-
VARCHAR可建完整索引(INDEX(col))或前缀索引(INDEX(col(191))),MySQL 8.0+ 支持最长 3072 字节前缀 -
TEXT字段**必须指定前缀长度**才能建索引,例如INDEX(content(255)),且这个长度选小了查不准,选大了索引膨胀 -
ORDER BY content或GROUP BY content在TEXT上极易触发Using filesort,甚至强制写磁盘临时表 - 全文检索可用
FULLTEXT索引,但VARCHAR和TEXT都支持,无差别;真正影响的是能否走覆盖索引
是否涉及高并发更新或主从同步?
TEXT 在写链路上的隐性成本常被低估:
- 大
TEXT字段更新会显著增大 binlog 体积,拖慢主从复制,尤其在STATEMENT格式下可能放大 N 倍 -
TEXT更新可能引发整行迁移(row movement),因为外置页指针要重写,而VARCHAR在未溢出时只是原地修改 - 备份工具(如
mysqldump、mydumper)对含大量TEXT的表更慢,压缩率也更低 - 如果字段内容极少变动(如文章正文),
TEXT影响可控;但如果像用户评论流那样高频增删改,优先压到VARCHAR能省不少麻烦
真正难的不是选类型,而是预估字段的“访问模式”:它是不是总和主键一起查?会不会被 ORDER BY 拖进慢查询?有没有可能某天突然塞进一篇 5MB 的 Markdown?这些比字节数更决定选 VARCHAR 还是 TEXT。











