为什么不推荐用select *

在 SQL 查询中直接使用 SELECT * 看似方便,但实际上会引入多种潜在问题。以下是主要原因及实际场景分析:

  1. 性能问题:数据传输与资源浪费
  • 数据冗余SELECT * 会返回表中所有字段,包括不需要的列(如大字段 TEXT/BLOB)。
代码语言:javascript代码运行次数:0运行复制
-- 假设表 `users` 包含 `id, name, bio (TEXT), avatar (BLOB)`
SELECT * FROM users WHERE id = 1;  -- 返回所有列(包含大字段)
SELECT id, name FROM users WHERE id = 1;  -- 仅返回必要字段

网络开销:大字段会显著增加数据传输量,尤其在分布式系统中。

内存占用:应用层处理冗余数据会消耗更多内存。

  • 索引失效:若查询未命中覆盖索引(Covering Index),需回表查询,降低效率。
代码语言:javascript代码运行次数:0运行复制
-- 索引 `idx_name` 仅包含 `name`
SELECT * FROM users WHERE name = 'Alice';  -- 需回表查主键索引获取其他列
SELECT name FROM users WHERE name = 'Alice';  -- 直接使用覆盖索引,无需回表
  1. 维护性问题:表结构变更的连锁反应
  • 字段顺序/数量变化:新增或删除列时,SELECT * 可能导致应用层解析错误。
    • 示例:原表有 id, name,新增 email 后,应用若按固定顺序解析字段可能出错。
  • JOIN 冲突:多表联查时,同名字段(如 id)会覆盖,需显式指定别名。
代码语言:javascript代码运行次数:0运行复制
-- 错误示例:两表的 `id` 列会冲突
SELECT * FROM users JOIN orders ON users.id = orders.user_id;

-- 正确做法:显式指定所需字段
SELECT users.id AS user_id, users.name, orders.order_date 
FROM users JOIN orders ON users.id = orders.user_id;
  1. 可读性与安全性
  • 代码不清晰:显式列名让查询意图更明确,便于后续维护。
代码语言:javascript代码运行次数:0运行复制
-- 模糊的查询
SELECT * FROM products WHERE price > 100;

-- 清晰的查询
SELECT product_id, product_name, price FROM products WHERE price > 100;
  • 数据泄露风险:若表中包含敏感字段(如 passwordtoken),SELECT * 会无意中暴露这些数据。
  1. 特殊场景的隐藏问题
  • 视图与存储过程:若视图使用 SELECT *,后续表结构变更可能导致视图未更新,引发逻辑错误。
  • ORM 框架映射:部分 ORM 工具(如 Hibernate)依赖列名映射对象属性,冗余字段可能导致映射失败。
最佳实践
  1. 显式指定所需字段:仅查询业务需要的列。
  2. 使用别名处理冲突:多表联查时明确字段归属。
  3. 定期审查查询:避免遗留代码中的 SELECT * 扩散。
    总结

SELECT * 虽然省事,但会带来性能损耗、维护隐患和安全风险。显式指定字段不仅能优化查询效率,还能提升代码健壮性,是数据库开发中的重要规范