text字段拖慢查询io,因其在innodb中常存于溢出页,导致每次访问需额外随机i/o;即使只查小字段,也可能加载整行或整页,造成无效io放大,且无法有效压缩或索引。

TEXT字段为什么拖慢查询IO
因为InnoDB的聚簇索引把整行数据(含TEXT内容)捆在一起存,哪怕你只SELECT id, title,MySQL也得把整页(16KB)从磁盘读上来,再过滤掉TEXT部分——这叫“无效IO放大”。更糟的是,TEXT实际内容常被存在溢出页(off-page),每次访问都要额外一次随机IO,比主键查询多2~3倍延迟。
压缩存储必须在应用层做
MySQL原生不支持TEXT字段自动压缩。别指望ROW_FORMAT=COMPRESSED对TEXT有效——它只压缩页结构,不碰溢出页里的大文本。真正能压的,是应用写入前用DeflaterOutputStream或zlib.compress()把字符串转成byte[]再存进BLOB字段。
- 纯文本压缩率通常60%~80%,但已压缩的PDF、图片再压无效,还白耗CPU
- 压缩后字段无法建索引,
LIKE和前缀索引全部失效,别对它加INDEX - 业务强依赖事务原子性(比如审计日志必须和主记录一起提交)时,这是唯一可行的库内方案
拆表隔离是见效最快的物理优化
把TEXT拎到单独的附属表,主表只留ID和结构化字段,所有列表页、统计查询都绕开TEXT。这不是妥协,是强制解耦。
- 主表
log_summary:存id、user_id、status、created_at等带索引字段 - 附属表
log_detail:存detail_id外键 +contentTEXT,可按月分区 +ROW_FORMAT=COMPRESSED - 查统计时只扫
log_summary,毫秒级;查原始内容才JOIN log_detail LIMIT 100
前缀索引不是万能解药,设错长度反而更慢
给TEXT字段建INDEX content(60),InnoDB只索引前60字符,超出部分仍要全表扫描。而且utf8mb4下60字符占240字节,远低于768字节硬限制,但选择性可能极低。
- 先测区分度:
SELECT COUNT(DISTINCT LEFT(content, 60)) / COUNT(*) FROM table,值 - 别盲目设长,100字符在utf8mb4下占400字节,索引体积暴涨,INSERT/UPDATE变慢
- 左模糊
LIKE '%关键词'和全模糊LIKE '%关键词%'永远走不了前缀索引,别试











