SELECT *在SQL视图中会引发结构变更风险,因视图仅快照创建时字段,不绑定后续表变更,导致新增列、删列报错、列序错位及嵌套视图风险放大,且绕过编译校验,使错误延至运行期。

在SQL视图中写 SELECT *,等于把底层表的结构变更风险直接透传给所有调用方——它不会报错,但会悄悄破坏数据契约。
视图创建时固化列定义,SELECT * 却不固化
MySQL/PostgreSQL 视图在 CREATE VIEW 时会解析并保存当前表的字段列表(列名、类型、顺序),但这个过程对 SELECT * 是“一次性快照”:只记录当时有哪些列,不绑定后续变更。一旦底层表执行 ALTER TABLE ADD COLUMN,视图定义不变,查询结果却多出一列;而如果执行 ALTER TABLE DROP COLUMN,视图下次调用直接报错 Unknown column 'xxx' in field list。
更隐蔽的问题是字段重排序:ALTER TABLE MODIFY COLUMN xxx FIRST 会让 SELECT * 返回的列序突变,下游按位置取值(如 rs.getString(2))立刻错位。
视图嵌套 + SELECT * = 风险放大器
当一个视图基于另一个用 SELECT * 定义的视图时,问题会叠加:
- 底层表加字段 → 中间视图不更新 → 上层视图查不到新字段,但也不报错
- 中间视图删字段 → 上层视图调用失败,错误堆栈指向上层,实际根因在中间层
- 字段类型变更(如
VARCHAR(50) → TEXT)→ 某些客户端驱动可能截断或转换失败,且无明确提示
SELECT * 在视图中彻底绕过编译时校验
显式写 SELECT id, name, email FROM users 的好处是:创建视图时数据库就检查这些字段是否存在、是否可读、是否类型兼容。缺失字段直接拒绝创建,强迫你面对问题。
而 SELECT * 放弃了这道防线——它把校验推迟到每次运行时,让错误从“构建期”滑向“运行期”,且常发生在高并发或关键路径上,排查成本陡增。
尤其危险的是与存储过程组合使用:存储过程调用该视图,再用 SELECT * 查存储过程结果集,字段错位可能一路穿透到应用层对象属性,引发 NullPointerException 或静默数据污染。
真正难处理的不是语法,而是隐性依赖
视图用 SELECT *,没人能快速回答:“这个视图到底返回哪些字段?哪些字段被下游哪几个报表或接口强依赖?新增字段会不会影响它们?”
这种模糊性会让 DBA 不敢轻易改表,开发不敢放心复用视图,审计时也难以确认敏感字段(如 password_hash、id_card)是否被无意暴露。显式列名不是多打几个字,而是把数据契约从“靠猜”变成“可验证”。

















