一、先拆解这段SQL代码
这段代码是标准的视图创建语句,我们逐行拆解它的作用:
CREATE OR REPLACE VIEW v_usa_vendors AS
SELECT vend_id,vend_name,vend_city,vend_state
FROM main.Vendors
WHERE vend_country = 'USA';
-
CREATE OR REPLACE VIEW v_usa_vendors AS- 核心动作:创建一个名为
v_usa_vendors的视图;如果该视图已经存在,就直接覆盖更新它的定义,无需先删除再重建。 - 命名规范:前缀
v_是行业通用约定,用来和普通数据表区分,一眼就能识别这是视图。
- 核心动作:创建一个名为
-
SELECT vend_id,vend_name,vend_city,vend_state- 定义视图要暴露的列:只保留供应商编号、名称、城市、州这4个字段,基表中其他列(比如供应商银行账号、联系人电话)不会出现在视图里。
-
FROM main.Vendors- 指定数据来源:视图的数据全部来自
main架构下的Vendors供应商表,这个表也叫基表。
- 指定数据来源:视图的数据全部来自
-
WHERE vend_country = 'USA'- 定义行级筛选规则:只保留国家为美国的供应商记录,其他国家的数据会被完全过滤掉。
二、视图的本质:到底什么是视图
视图(View)是SQL中的虚拟表,这是理解它的第一性原理:
- 视图不存储任何真实数据:它本身只是一段被命名、被保存起来的
SELECT查询语句,没有自己的数据文件。你看到的所有行和列,都来自底层基表的实时计算。 - 使用上和普通表完全一致:你可以像查询普通表一样对视图执行
SELECT、加筛选条件、关联其他表,语法没有任何区别。
用会计场景做类比:
- 基表
Vendors相当于企业的全套供应商档案台账,里面记录了所有供应商的全部信息,是原始数据的载体。 - 视图
v_usa_vendors相当于你定制的美国供应商专用报表模板:模板里提前设好了筛选条件和显示字段,每次打开模板都会自动从台账里取最新数据生成结果;模板本身不存数据,数据变更都发生在原始台账上。
三、视图的核心价值:为什么要用视图
视图是典型的“逻辑封装工具”,核心价值不在性能,而在简化、安全、统一口径,主要有4个作用:
1. 简化复杂查询,降低使用门槛
把多表关联、多层嵌套、复杂计算的SQL封装成视图,业务人员不用理解底层表结构,直接 SELECT * FROM 视图 就能拿到结果。
比如你这个美国供应商视图,后续任何人要查美国供应商,都不用再记筛选条件和字段名,直接查视图即可。
2. 数据权限管控,实现字段/行级脱敏
这是企业级系统里视图最常用的场景:
- 列级安全:隐藏敏感字段。比如供应商表有银行账号、联系人手机号,视图只暴露名称和地址,普通员工只能访问视图,接触不到敏感数据。
- 行级安全:限制可见数据范围。比如这个视图只让美国区运营看到美国的供应商,看不到其他国家的供应商数据。 就像会计岗位的权限分离:出纳只能看资金账,看不到成本利润明细,视图就是实现这种权限隔离的常用手段。
3. 统一数据口径,避免统计偏差
当多个报表、多个部门都用到同一份逻辑时,把逻辑固化成视图,保证所有人取数规则一致。 比如“美国供应商”的定义,如果每个人自己写SQL,可能有人漏了筛选条件、有人用了不同的字段,最终统计结果对不上。视图定义一次,全局复用,从根源上统一口径。
4. 兼容上层应用,屏蔽表结构变更
如果底层基表因为业务重构拆分、合并了字段,可以通过视图保持对外的表结构不变,上层应用、报表系统不用修改代码,实现平滑过渡。
比如原来的 Vendors 表拆成了供应商基础表和供应商地址表,你可以通过视图把两表关联起来,对外仍然呈现原来的字段结构,老程序无需改动。
四、视图的底层执行原理
很多初学者会误以为“视图是预编译的,查询更快”,这是非常常见的误区。
当你执行:
SELECT * FROM v_usa_vendors WHERE vend_state = 'CA';
数据库内部的实际执行步骤是:
- 解析SQL,识别出
v_usa_vendors是视图; - 从系统数据字典中取出视图的定义语句(也就是你创建视图时写的那段SELECT);
- SQL合并重写:把外层的查询条件和视图内部的查询逻辑合并成一条完整SQL,等价于:
SELECT vend_id,vend_name,vend_city,vend_state FROM main.Vendors WHERE vend_country = 'USA' AND vend_state = 'CA'; - 查询优化器对这条合并后的SQL生成执行计划,然后访问基表取数。
结论:普通视图不会提升查询性能,它的执行效率和你直接写完整SQL完全一样。如果视图里嵌套了视图(视图A里面又引用了视图B),反而会增加优化器的解析成本,可能导致性能下降。
五、视图的常见操作
1. 查询视图
和普通表完全一致,支持筛选、排序、分组:
-- 查询美国加州的供应商
SELECT vend_name, vend_city
FROM v_usa_vendors
WHERE vend_state = 'CA'
ORDER BY vend_name;
2. 更新视图(有严格限制)
视图本身没有数据,对视图执行 INSERT/UPDATE/DELETE,本质是修改底层基表的数据。
但只有“简单视图”才支持更新,必须同时满足:
- 只基于单张基表,没有多表JOIN;
- 没有聚合函数(SUM/COUNT/AVG等)、没有GROUP BY、没有DISTINCT、没有UNION;
- 没有计算列、没有子查询。
你写的这个 v_usa_vendors 就属于可更新视图,执行:
UPDATE v_usa_vendors SET vend_city = 'New York' WHERE vend_id = 1001;
会直接修改 Vendors 基表中对应行的数据。
反之,如果视图是多表关联、带分组统计的,就无法更新——数据库不知道该把修改映射到基表的哪一行。
3. 删除视图
DROP VIEW IF EXISTS v_usa_vendors;
删除视图只会删除视图的定义,不会影响底层基表的任何数据。
六、优缺点与最佳实践
优点
- 代码复用,减少重复SQL编写
- 精细化权限控制,保障数据安全
- 屏蔽底层复杂度,降低业务人员使用门槛
- 统一数据口径,减少统计不一致问题
缺点
- 不存储数据,复杂视图每次查询都要重新计算,性能取决于基表和索引
- 多层嵌套视图会严重劣化性能,且排查问题困难
- 可更新性限制多,复杂视图无法直接写数据
- 容易隐藏复杂度,维护者可能误以为视图很简单,忽略底层的多表关联逻辑
最佳实践
- 命名统一加前缀(如
v_),和物理表区分开; - 定义视图时明确写列名,禁止用
SELECT *,避免基表加字段后视图不同步; - 尽量不要嵌套视图,最多一层,禁止三层以上嵌套;
- 高频访问、数据实时性要求不高的场景,优先用物化视图(Materialized View,会真实存储数据,定时刷新)而非普通视图;
- 视图只做逻辑封装,不要在视图里写过于复杂的业务计算。