不建议使用 SELECT *,因其导致字段顺序依赖表结构、无法利用覆盖索引、增大IO与网络开销、引发ORM映射异常、降低SQL可读性及权限管控风险;仅适用于临时排障、表结构探索等有限场景。

直接用 SELECT * 能查出所有字段,但不建议在生产环境或明确需求时这么写。
为什么 SELECT * 在实际开发中常被劝退
它看似省事,实则埋了几个隐性成本:
- 字段顺序依赖表结构,一旦 ALTER TABLE 增删改列,应用层可能因字段错位解析失败(尤其用
ResultSet.getObject(1)这类按索引取值的场景) - 数据库无法利用覆盖索引优化,哪怕你只关心 2 个字段,也会把整行数据从磁盘/缓冲区拉出来,IO 和网络开销翻倍
- ORM 映射容易出问题,比如 MyBatis 的
<resultMap>若没显式声明字段,*返回的别名可能和 Java 属性名不一致 - SQL 可读性差,别人一眼看不出这个查询到底要什么,也难做权限收敛(比如不该暴露
password_hash字段)
SELECT * 真正适合的几个场景
不是完全不能用,关键看上下文:
- 临时排障:在 MySQL 客户端或 DBeaver 里快速看一眼某条记录全貌,
SELECT * FROM users WHERE id = 123; - 表结构探索:刚接手一个陌生库,
SELECT * FROM information_schema.columns WHERE table_name = 'orders'; - ETL 中间步骤:用 Spark SQL 或 Flink SQL 做宽表拼接时,阶段性保留全部字段便于调试(但最终输出必须显式指定)
替代方案:如何安全又高效地查“所有字段”
如果业务逻辑确实需要当前表全部字段(比如导出报表、备份快照),推荐这些做法:
- 显式写出所有字段名:
SELECT id, name, email, created_at FROM users;—— 虽然多打几下键盘,但语义清晰、可维护性强 - 用 IDE 或 CLI 工具自动生成字段列表:DBeaver 右键表 → “Generate SQL” → “Select Statement”;MySQL 命令行可用
SHOW COLUMNS FROM users;辅助复制 - 对宽表(50+ 列)且字段稳定,可封装视图:
CREATE VIEW users_export AS SELECT id, name, email, ... FROM users;,后续只查SELECT * FROM users_export; - 若用 Python + SQLAlchemy,可用
table.columns.keys()动态生成字段列表,避免硬编码(但注意别在循环里反复反射)
真正麻烦的从来不是写几个字段名,而是当某天 SELECT * 突然变慢、报错或返回空值时,你得花半小时倒查是不是新加的 JSON 字段触发了隐式转换,或者某个字段被加了 GENERATED ALWAYS 行为。

















