避免 SELECT * 是数据库开发中的一条重要原则,主要基于以下几个核心原因:
1. 性能浪费
- 不必要的 I/O :读取不需要的列会增加磁盘 I/O,尤其当表包含大字段(如
TEXT、BLOB、长字符串)时,代价巨大。 - 内存与 CPU 开销:数据库需要将多余的数据加载到内存,并进行解析、传输,消耗更多 CPU 和内存资源。
2. 网络传输负担
- 在客户端与数据库分离的场景(如应用程序服务器 + 数据库服务器),
SELECT *会传输大量无用数据,增加网络延迟,尤其在云环境或跨机房部署时影响显著。
3. 索引无法有效覆盖
- 如果只需要少数几个字段,可以创建覆盖索引 ,直接通过索引返回数据(
Using index),避免回表查询。
使用SELECT *会强制回表,即使查询条件用到了索引,性能也会大打折扣。
4. 可读性与维护性差
- 表结构变化引发隐患 :当表增加新列,
SELECT *会无差别返回所有列。如果应用代码未正确处理新增列(例如按位置取列值),可能导致程序异常或数据错乱。 - 意图不清晰:阅读代码的人不知道实际需要哪些字段,增加维护难度。
5. 连接操作(JOIN)时的膨胀
- 多表 JOIN 时使用
SELECT *会返回所有参与表的全部列,极易产生重复列名(如id、name),并导致结果集行数不变但列数爆炸,浪费大量内存和网络资源。
✅ 正确做法
- 只选择需要的列 :
SELECT col1, col2 FROM table - 明确列名 :即使在
INSERT ... SELECT或临时调试时也尽量列出字段 - 利用工具/框架:ORM(如 MyBatis、Hibernate)中只映射必要字段
📌 唯一例外(可接受使用 SELECT *)
- 极低频率的临时查询 (手动
SELECT *看一眼数据样本) - 已知表只有少数几列且未来不会变化(如配置表、字典表)
- 使用
EXISTS子查询时 (SELECT *会被优化器忽略,写SELECT 1更规范)
💬 面试回答模板
"避免
SELECT *主要是为了性能、网络和可维护性。它会额外读取不需要的列,增加磁盘 I/O 和网络传输;无法利用覆盖索引,容易导致回表;同时表结构变更时可能引发未知错误。最佳实践是始终显式列出所需字段。"