在sql视图中禁用select *,因其导致列结构不可控、跨平台不一致、列名冲突、解析失败、性能下降及工具链失效。

在 SQL 视图中写 SELECT * 不是语法错误,但等于主动交出对输出结构的控制权——视图一旦创建,列名、列序、列数就该是确定的,而 * 让它变成运行时才决定的黑盒。
视图字段会随底层表变更静默失效
视图定义只存 SQL 文本,不固化元数据。用 SELECT * 创建后:
- 后续执行
ALTER TABLE ADD COLUMN updated_at DATETIME,查询视图会立刻多出一列,但视图定义里根本没这行代码 - 下游应用若按位置取值(如
rs.getString(2)),或 BI 工具靠列名自动映射,就会拿到错的数据甚至直接报错 - MySQL 中
ALTER TABLE ... FIRST / AFTER改字段位置后,视图返回的列序可能变化,但定义不变——错位不报错,只静默错位
多表 JOIN 时必然触发列名冲突
SELECT * 在涉及多个表时几乎必报错:
- 两个表都有
id、name、created_at字段?数据库当场拒绝:Column 'id' is ambiguous - 必须显式限定:用表别名前缀,比如
users.id AS user_id、orders.id AS order_id - 含空格或特殊字符的字段(如
[E-mail Address])必须加方括号,否则解析失败 - 同语义字段需统一别名(如
users.full_name AS name和admins.display_name AS name),否则下游硬编码依赖原始名会崩
覆盖索引和执行计划彻底失控
视图里写 SELECT * 会让外层查询无法下推优化:
- 外层加
WHERE created_at > '2026-01-01',优化器无法保证把它下推到基表扫描前,可能先拉全字段再过滤 - 外层加
LIMIT 10,但视图里含ORDER BY score DESC→ MySQL 可能忽略LIMIT,PostgreSQL 可能全量排序后截断 - 想对视图结果
JOIN其他表,但视图返回了冗余大字段(如TEXT或JSON)→ 内存膨胀、哈希表构建变慢 - MySQL 5.7+ 默认用
TEMPTABLE算法处理含子查询的视图,外层WHERE根本没机会参与谓词下推
工具链和 ORM 映射直接失效
MyBatis 的 resultMap、JPA 的 @Column、Power BI 的自动列推断,全都依赖稳定且可预测的列名与顺序:
- 源表新增字段后,
SELECT *视图返回的列序可能变化,导致 MyBatis 把新字段值错映射到老字段属性上 - Power BI 刷新报表时提示 “column not found” 或列类型错乱
- Java 应用用
ResultSet.getObject(i)按索引取值,拿到完全无关的数据 - 视图用
SELECT *创建后,底层表加字段不会自动同步到视图定义中,查出来永远少一列
最麻烦的不是语法本身,而是它掩盖了数据契约——你到底要什么字段、谁在消费、下次加列时会不会崩。漏掉一个 created_at 可能让业务日志少关键时间戳,多查一个 user_avatar 可能让接口慢 200ms。










