SELECT *会让查询变慢,因其强制返回所有字段,引发磁盘I/O增加(如大字段溢出页读取)、网络传输膨胀、内存压力翻倍,并大概率绕过覆盖索引导致回表或全表扫描。

生产环境严禁使用 SELECT *,不是因为语法错,而是它会悄悄放大性能、维护和安全风险——尤其在高并发或宽表场景下,后果立竿见影。
为什么 SELECT * 会让查询变慢
数据库要返回所有字段,哪怕你只用其中一两个。这直接带来三重开销:
- 磁盘 I/O 增加:InnoDB 对超过 728 字节的字段(如
TEXT、BLOB、长VARCHAR)会额外做一次溢出页读取,SELECT *强制触发这些操作 - 网络传输膨胀:应用层和 DB 之间多传几 MB 数据,带宽和延迟肉眼可见上升,微服务间调用尤其敏感
- 内存压力翻倍:JVM 或 Python 进程得为整行数据分配对象,GC 频率升高,甚至
OutOfMemoryError
更隐蔽的是:一旦表里有大字段,SELECT * 几乎必然绕过覆盖索引。比如 WHERE status = ? 走了 status 索引,但因要回表取所有列,优化器可能直接放弃索引、改走全表扫描。
SELECT * 怎么破坏代码稳定性
字段顺序和数量不再是契约,而是“运气”:
- ALTER TABLE ADD COLUMN 新增字段后,
ResultSet.getObject(2)这类按位置取值的 JDBC 代码立刻错位 - ORM 映射(如 MyBatis 的
resultMap)若未显式声明字段,新增 NOT NULL 字段没默认值时直接抛SQLException - 视图用
SELECT *创建后,底层表加字段不会自动同步到视图定义中,查出来永远少一列
这不是理论风险——线上故障日志里常见 Column index out of range 或 Cannot convert value 'xxx' to type 'java.lang.Integer',根因就是 SELECT * 掩盖了字段依赖。
哪些场景下它看起来“能用”,但其实埋雷
别被开发期的“快”骗了:
- 本地调试用
SELECT *查数据?没问题。但脚本一旦进 CI/CD 或监控定时任务,字段变更就成定时炸弹 - 小表(
- Django 的
Model.objects.all()默认生成SELECT *?必须配合.values('a', 'b')或.only('a', 'b')收口
真正麻烦的从来不是写多几个字段名,而是 SELECT * 让人不再思考:这一查到底要什么数据、谁在用、生命周期多长、变更成本几何。

















