1. 概述
使用SQL数据库时,我们可能需要创建视图来表示一个或多个表的数据。视图类型多样,但核心区别在于:视图是仅作为查询的简化封装,还是通过缓存数据来提升访问性能。因此我们区分普通SQL视图(简单或复杂)和物化视图——后者将视图数据作为缓存存储。
本文将通过实际案例,对比普通视图(简单/复杂)与物化视图的差异。
2. 为什么需要视图
视图本质是存储在数据库中的命名SQL语句,相当于展示一个或多个表数据子集的虚拟表。
假设我们有一个需要频繁复用或暴露给Web应用的查询。通过视图,我们可以为这个查询命名并存储在数据库中。
视图能提升语句可读性,特别是当查询涉及跨库表连接时。从安全角度,我们可以通过视图权限控制隐藏敏感信息(如薪资字段)。
此外,我们还会看到物化视图如何实现查询性能扩展。
先看这个常用子查询语法:
SELECT * FROM
(
SELECT
column1,
column2
FROM
some_table
) s;
这种子查询可称为内联视图。所有视图都基于相同概念,但额外使用DDL命令将查询存储为可复用语句。
3. 数据库示例
以PostgreSQL为例,创建员工-部门测试数据库。首先定义包含id和name的部门表:
CREATE TABLE department (
department_id int8 NOT NULL,
department_name varchar(255) NOT NULL,
CONSTRAINT department_id_pkey PRIMARY KEY (department_id)
);
再定义员工表,包含部门外键:
CREATE TABLE employee (
employee_id int8 NOT NULL,
employee_name varchar(255) NOT NULL,
department_id int8 NOT NULL,
salary int8 NOT NULL,
CONSTRAINT empolyee_id_pkey PRIMARY KEY (empolyee_id),
CONSTRAINT fk_department_department_id FOREIGN KEY (department_id) REFERENCES department(department_id)
);
4. 普通视图与复杂视图
当查询资源消耗低且结果频繁变化时,适合使用普通或复杂视图。
4.1. 普通视图
普通视图仅基于单个基表,即只从一张表获取数据。
假设需通过Web应用展示员工信息,但需隐藏薪资字段。我们可以创建只显示id和name的视图,并对非管理员用户授予该视图权限,隐藏原始表。
创建普通视图:
CREATE VIEW employee_details AS
SELECT
employee_id,
employee_name
FROM employee;
创建后可像表一样查询:
SELECT employee_id, employee_name
FROM employee_details;
4.2. 复杂视图
复杂视图包含多个基表,且可能使用GROUP BY、DISTINCT、表达式计算列或聚合函数。
先创建连接部门表的视图:
CREATE VIEW employee_department AS
SELECT
e.employee_id,
e.employee_name,
d.department_name
FROM employee e
INNER JOIN department d ON e.department_id = d.department_id;
同样可查询:
SELECT employee_name, department_name
FROM employee_department;
再看更复杂的聚合视图——按部门统计薪资:
CREATE VIEW department_salary AS
SELECT
d.department_id,
d.department_name,
COUNT(e.*) AS employee_count,
SUM(e.salary) AS total_salary
FROM department d
INNER JOIN employee e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
由于视图可视为表,可对其添加WHERE条件:
SELECT department_id,
department_name,
employee_count,
total_salary
FROM department_salary
WHERE department_id = 2;
4.3. 视图上的DML操作
虽然不推荐,但可通过视图执行DML操作(INSERT/DELETE/UPDATE)。例如更新员工姓名:
UPDATE employee_details
SET employee_name = 'Eric Johnson'
WHERE employee_id = 6;
⚠️ 仅限单表普通视图支持DML,复杂视图无法直接执行。
5. 物化视图
物化视图直接存储查询结果集。当面对包含子查询、连接和聚合的昂贵查询时,保存结果集可显著提升性能。因此常用于需要常量时间访问的大数据集。
不同数据库对物化视图支持差异很大:
- ✅ PostgreSQL:提供DDL命令,但需手动刷新数据
- ✅ Oracle:面向数据仓库设计,支持定时/提交刷新等高级功能(通过物化视图日志实现增量刷新)
- ❌ MySQL:无内置支持,需借助LeapDB等插件
以PostgreSQL为例,创建部门薪资统计的物化视图:
CREATE MATERIALIZED VIEW materialized_department_salary AS
SELECT d.department_id,
d.department_name,
COUNT(e.*) AS employee_count,
SUM(e.salary) AS total_salary
FROM department d INNER JOIN employee e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
可带条件查询:
SELECT *
FROM materialized_department_salary
WHERE department_id = 5;
关键点:物化视图本质是表,可创建索引或分区提升性能。例如添加索引:
CREATE UNIQUE INDEX ON materialized_department_salary (
department_id,
employee_count,
total_salary
);
6. 普通视图与物化视图的核心差异
特性 | 普通视图(简单/复杂) | 物化视图 |
---|---|---|
数据存储 | 仅存储查询逻辑 | 物理存储结果集 |
数据时效性 | 实时(每次查询重新执行) | 静态快照(需手动/定时刷新) |
性能影响 | 查询复杂度决定性能 | 预计算数据,访问速度快 |
适用场景 | ✅ 安全控制 ✅ 查询简化 |
✅ 大数据分析 ✅ 离线访问 |
DML操作 | 简单视图支持 | 通常不支持(需特殊配置) |
扩展能力 | ❌ 不可索引/分区 | ✅ 支持索引/分区 |
简单粗暴总结:
- 普通视图:安全隔离的"虚拟表",每次查询都重新计算
- 物化视图:性能优化的"数据缓存",牺牲实时性换取速度
⚠️ 随着NoSQL(如键值存储)兴起,传统视图使用率下降,但物化视图仍在数据分析领域广泛应用。
7. 结论
本文对比了普通视图与物化视图的核心差异:
- 普通视图(简单/复杂):每次访问都重新执行查询,主要用于安全控制和查询简化
- 物化视图:存储物理数据快照,通过预计算提升性能,适合大数据分析场景
物化视图可应用索引和分区优化,而普通视图则更侧重访问控制。在选择时需权衡实时性与性能需求——普通视图保证数据最新但可能较慢,物化视图访问飞快但数据可能非最新。
踩坑提醒:MySQL用户需注意其原生不支持物化视图,Oracle/PostgreSQL则提供更完善的实现方案。