应避免select *含text字段,因其会强制加载全文至内存,导致中间结果膨胀、传输变慢、优化器失效;推荐用substring截取预览、建md5摘要索引或垂直拆表优化。

为什么不能直接 SELECT * 含 TEXT 字段
只要查询语句里出现 SELECT * 或显式包含 TEXT、LONGTEXT 等大字段,MySQL 就会把整块内容加载进内存——哪怕你只打算看前 10 个字符。这会导致:
• 中间结果集体积暴增,尤其在 JOIN 或子查询中;
• 网络传输变慢,应用层解析压力上升;
• 优化器无法有效剪枝,EXPLAIN 显示的 rows 和 bytes 常远超预期。
用 SUBSTRING 提取前 N 字符做简略预览
最轻量、兼容性最强的方式是用 SUBSTRING()(或 LEFT())截取开头部分,避免加载全文:
SELECT id, title, SUBSTRING(content, 1, 200) AS content_preview FROM articles;
注意点:
• SUBSTRING(content, 1, 200) 不会触发全字段读取,优化器通常能跳过 LOB 页加载;
• 若字段为 UTF8MB4,200 是字节数而非字符数,中文可能被截断,稳妥起见可用 SUBSTRING(content, 1, 100);
• 不要在 WHERE 或 ORDER BY 中对 SUBSTRING(content, ...) 做条件或排序,否则仍会全扫。
用 MD5 + 前缀建摘要索引替代模糊匹配
当需要“判断内容是否重复”或“快速等值过滤”,又不能给 LONGTEXT 加常规索引时,可建摘要列:
- 新增列
content_md5 CHAR(32),用触发器或应用层写入时同步计算MD5(SUBSTRING(content, 1, 1000)) - 对
content_md5建普通 B+ 树索引:ALTER TABLE docs ADD INDEX idx_content_md5 (content_md5); - 查询时改用:
SELECT * FROM docs WHERE content_md5 = MD5(SUBSTRING('待查文本', 1, 1000));
这个方案绕开了 TEXT 索引限制,且比全文索引更轻量,适合判重、版本比对等场景。
垂直拆表:把 TEXT 字段单独拎到关联表
如果业务上 90% 的查询只读元数据(id、title、created_at),极少访问正文,就该物理隔离:
CREATE TABLE articles_body ( article_id BIGINT PRIMARY KEY, content LONGTEXT, updated_at TIMESTAMP );
后续查列表页时只连主表:SELECT id, title, created_at FROM articles;
查详情页再按需 JOIN articles_body。这样既避免大字段污染高频路径,又让缓存更有效——articles 表体积小、热数据易驻留内存。
真正容易被忽略的是:即使你没在 SQL 里写 TEXT 字段,只要视图、CTE 或子查询定义里包含了它,MySQL 仍可能把它拖进中间结果。检查执行计划时,盯住 Extra 列是否出现 Using temporary 或 Using filesort,那往往就是大字段在后台悄悄膨胀了。










