生产环境严禁使用SELECT *,因其加重网络与IO负担(如TEXT字段导致多倍数据传输和溢出页读取)、彻底破坏覆盖索引(引发回表、I/O翻倍,实测慢47倍)、暴露敏感字段并引发ORM/DTO兼容性故障,还干扰优化器生成稳定执行计划。

因为在生产环境里,SELECT * 看似省事,实则埋下性能、安全和维护三重隐患。
加重网络与IO负担
数据库要返回所有列,哪怕前端只用其中2个字段——多余字段尤其是 TEXT、BLOB、长 VARCHAR 会显著拉高单次查询的数据体积。实测中,一个含 address(TEXT)和 avatar_url(长字符串)的用户表,SELECT * 比 SELECT id, name, email 多传 6–8 倍数据量。跨机房或高延迟链路下,传输耗时直接翻倍。InnoDB 还会对超长字段单独做溢出页存储,读一行可能触发多次磁盘随机 I/O。
彻底破坏覆盖索引机会
覆盖索引要求“查询所需字段全部落在同一个索引中”,这样 MySQL 就能只查索引树,不回主键表。例如:
-
高效:有联合索引
(status, created_at, title),执行SELECT title, created_at FROM posts WHERE status = 1→ 走索引、不回表、EXPLAIN显示Using index -
低效:同样条件写
SELECT * FROM posts WHERE status = 1→ 即便索引能定位记录,仍需用主键去聚簇索引捞 full row → 多一次 B+ 树遍历,I/O 次数翻倍
500 万行商品表上,前者响应 3ms,后者达 141ms,差距 47 倍。
引发隐性故障与安全风险
表结构一旦新增敏感列(如 id_card、password_hash、internal_note),SELECT * 会自动把它们吐给应用层,轻则日志泄露、重则接口越权暴露。更隐蔽的是兼容性问题:ORM 映射、DTO 解析、前端字段绑定都依赖固定列集,加一列、删一列、改类型,SELECT * 很可能让服务突然抛 SQLException 或空指针。
干扰优化器与执行计划稳定性
MySQL 查询优化器需要预估结果集大小、内存占用、排序成本等。面对 SELECT *,它无法判断哪些列真正被使用,常被迫选择保守执行路径(如放弃索引合并、强制临时表、禁用松散索引扫描)。同时,统计信息更新、字符集变更、甚至 minor 版本升级,都可能让同一句 SELECT * 在不同时间生成完全不同的执行计划,排查难度陡增。










