TEXT/BLOB在InnoDB中触发行溢出:超约8098字节即外存至溢出页,主记录仅留20字节指针;Compact格式存前768字节+指针,Dynamic格式全外存,导致额外随机I/O、禁用自适应哈希、强制磁盘临时表、SELECT *性能骤降。

直接说结论:TEXT 和 BLOB 类型在 InnoDB 中会触发行溢出存储,导致查询变慢、内存开销陡增、索引能力受限,且极易引发磁盘 I/O 瓶颈——这不是“不推荐”,而是线上高并发 OLTP 场景下事实上的禁用项。
TEXT/BLOB 触发行溢出后,InnoDB 怎么存数据?
默认 16KB 的 InnoDB page 中,是否把 TEXT/BLOB 数据放进来,取决于「能不能塞下至少两行」。实际阈值约 8098 字节;超过就溢出。
- Compact/Redundant 行格式(Antelope):前
768字节仍留在主 page,其余存溢出页,靠指针关联 - Compressed/Dynamic 行格式(Barracuda):只留
20字节指针,全部内容外置——更省主 page,但每次读都要额外随机 IO - 哪怕只超 1 字节(比如 769 字节),也会强制分配整个溢出页(16KB),空间浪费严重
- 溢出页不支持自适应哈希索引(Adaptive Hash Index),WHERE 条件查 TEXT 字段必须全字段比对,无法加速
为什么 SELECT * 或临时表会让性能雪崩?
一旦涉及 TEXT/BLOB 字段,MySQL 就无法使用内存临时表(MEMORY 引擎),只能退化为磁盘临时表(MyISAM 或 InnoDB),I/O 成倍放大。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
-
ORDER BYTEXT 字段时,默认只按前1024字节排序(由max_sort_length控制),结果不可靠 -
GROUP BY、DISTINCT同样受max_sort_length限制,可能误判重复 -
SELECT *会把整段溢出数据拉进 buffer pool,挤占其他热数据空间,缓存命中率骤降 - 备份工具(如
mysqldump)读取 TEXT 字段时,容易因单次 fetch 过大触发超时或 OOM
TEXT 和 VARCHAR 到底怎么选?
不是“能存下就用 TEXT”,而是优先用 VARCHAR,哪怕设到 VARCHAR(16383)(utf8mb4 下约 65532 字节)也强于 TEXT。
-
VARCHAR在长度 ≤ 768 字节时,完全行内存储;即使略超,在 Compact 格式下仍保留前缀,访问成本可控 -
TEXT无长度声明,但建表时隐式启用溢出逻辑,哪怕你只存 10 字节,InnoDB 也按溢出路径处理 - 如果字段平均长度稳定在 10KB 以内,用
MEDIUMTEXT不如拆成VARCHAR(8192)+ 单独扩展表(如_ext后缀) - 真正需要 TEXT 的场景极少:例如用户提交的原始日志全文、法律合同原文、未结构化的 JSON 片段(且不需 WHERE 查询)
替代方案比硬扛 TEXT 更有效
多数所谓“必须存大文本”的需求,其实只是设计没分层。
- 图片/音视频:绝对不要存
BLOB,改存 URL 路径,用对象存储(如 S3、OSS、MinIO)托管 - 富文本内容(如文章正文):主表只存摘要、标题、状态;长文单独建
article_contents表,按需 JOIN - JSON 配置类字段:若需按 key 查询,拆成独立列;若纯透传,用
JSON类型(MySQL 5.7+),它支持生成列和函数索引 - 日志类数据:直接写入 Elasticsearch 或 Loki,别塞进 MySQL;MySQL 只存关键元信息(trace_id、status、耗时)
最常被忽略的一点:TEXT 字段带来的性能衰减不是线性的,而是随数据量增长呈指数级恶化——等单表涨到 10GB+、QPS 开始抖动时再重构,代价远高于初期多花半小时做字段拆分。

















