子查询中使用SELECT *会强制加载BLOB/TEXT等大字段到内存,导致中间结果膨胀、IO和内存压力剧增;应逐层显式指定所需字段,避免在WHERE、JOIN或排序中直接引用TEXT,改用全文索引、截取存储或CAST转换优化。

子查询里 SELECT * 会把 BLOB/TEXT 一起拖下来
嵌套查询中如果某层用了 SELECT *,而底层表含 BLOB 或 TEXT 字段,这些大字段就会被完整读入内存、参与中间结果集传输和排序——哪怕外层根本不用它们。MySQL 5.7+ 和 PostgreSQL 都不会自动剪掉未引用的大字段,尤其在视图或 CTE 封装后更难优化。
实操建议:
- 每一层嵌套只
SELECT真正需要的字段,显式排除BLOB/TEXT列(如SELECT id, name, created_at FROM orders) - 若必须返回大字段,确保它只出现在最外层,且有明确业务理由(如导出详情页)
- 用
EXPLAIN FORMAT=JSON(MySQL)或EXPLAIN (ANALYZE, BUFFERS)(PostgreSQL)检查rows和bytes是否异常膨胀
WHERE 条件里对 TEXT 字段做 LIKE 模糊匹配会强制全表扫描
WHERE content LIKE '%keyword%' 这类写法无法走索引,嵌套在子查询里更危险:数据库可能先拉出全部 TEXT 内容再过滤,IO 和内存压力陡增。即使加了前缀索引(如 content(255)),% 开头也无法利用。
实操建议:
- 改用全文索引:
ALTER TABLE docs ADD FULLTEXT(content),配合MATCH(content) AGAINST('keyword') - 业务允许时,把关键词提取后存入独立的
keywords字段,建普通索引 - 避免在子查询的
WHERE中直接操作TEXT,优先把过滤逻辑下推到 JOIN 表或主表条件中
JOIN 时关联字段含 TEXT 类型会导致性能断崖
用 TEXT 字段做 JOIN 键(如 LEFT JOIN logs ON l.trace_id = t.id,其中 t.id 是 TEXT)会触发隐式转换、哈希计算开销剧增,MySQL 可能直接拒绝执行并报错 Error 1170: BLOB/TEXT column 'id' used in key specification without a key length。
实操建议:
-
TEXT字段绝不能作为JOIN、GROUP BY或ORDER BY的依据,必须转为VARCHAR(N)并加索引 - 若原始数据超长,用
SUBSTRING(trace_id, 1, 64)截取后存为新列,并确保两端一致 - 确认执行计划中
type是ref或eq_ref,不是ALL或index_merge
MySQL 8.0+ 中子查询引用 TEXT 字段仍可能触发临时磁盘表
即使你没在 SELECT 列表里选 TEXT,只要子查询的 WHERE、ON 或 HAVING 引用了它,优化器仍可能因无法估算大小而将中间结果写入磁盘临时表(Using temporary; Using filesort),尤其当 sort_buffer_size 不足时。
实操建议:
- 检查
SHOW SESSION STATUS LIKE 'Created_tmp%',若Created_tmp_disk_tables持续增长,说明频繁落盘 - 调大
tmp_table_size和max_heap_table_size(需两者一致),但别超过物理内存 20% - 用
CAST(col AS CHAR(255))替代直接引用,让优化器更容易估算长度
嵌套查询里处理大文本字段,真正麻烦的不是语法能不能跑通,而是它悄无声息地把内存吃光、把磁盘 IO 拉满、把执行计划带偏——而且往往只在数据量上十万后才暴露。










