生产环境严禁无条件使用select *,因其强制读取所有字段导致磁盘i/o增加、网络传输膨胀、内存压力翻倍,并大概率绕过覆盖索引引发回表或全表扫描,同时带来字段变更兼容性、敏感信息泄露及代码维护风险。

直接用 SELECT * FROM table_name; 就能查出全部数据,但生产环境里不建议无条件裸用 *。
为什么 SELECT * 要谨慎用
它确实最省事,但背后有实际代价:
- 数据库要读取并传输所有字段,哪怕你只关心其中 2 列,网络和 I/O 开销都白涨
- 表结构一旦加了新字段(比如新增
updated_at或 JSON 类型列),应用层可能因字段数/类型突变而解析失败 - 无法利用覆盖索引:如果只查
id, name,而有个联合索引(id, name),MySQL 可能连主键都不用回表;但SELECT *通常会强制回表取全行 - 某些 ORM 或中间件对
*的列序假设不稳定,尤其跨 MySQL 版本时
什么场景下可以放心用 SELECT *
不是不能用,而是得看上下文:
- 临时排障或本地开发查数据,比如
SELECT * FROM employees LIMIT 10;快速看样例 - 表极小且字段稳定(比如配置表
app_config只有 4 列,半年没改过) - 明确需要所有字段,且已确认后续无字段膨胀风险(例如日志归档表,只写不改)
- 配合
LIMIT使用,避免扫全表,如SELECT * FROM logs ORDER BY id DESC LIMIT 20;
SELECT * 和显式列名的性能差异在哪
差别不在语法本身,而在执行计划和资源消耗:
- 显式写
SELECT id, name, email时,MySQL 能更早确定所需字段,可能跳过某些大字段(如TEXT、BLOB)的磁盘读取 - 如果查询走的是二级索引,而你要的字段全在该索引里(覆盖索引),
SELECT id, status可能完全不访问主键 B+ 树;但SELECT *一定会触发回表 -
EXPLAIN看Extra字段:出现Using index是好事,出现Using where; Using filesort或Using temporary就得警惕了
容易被忽略的边界问题
真正出问题的地方往往藏在细节里:
-
SELECT *在视图或子查询中可能放大问题——视图定义若含*,上游表加字段后,视图输出列数就变了 - 使用
mysqldump导出时默认带--skip-extended-insert,但若表里有GENERATED列或虚拟列,*仍会把它们拉进来,而某些客户端不识别 -
SELECT *配合ORDER BY和大偏移量(如LIMIT 10000, 20)时,MySQL 仍需扫描前 10000 行,此时显式指定关键排序字段+索引更可控











