物化视图的定义
物化视图是一种预先计算并存储查询结果的数据库对象。与普通视图不同,普通视图只是一个 SQL 查询的定义,每次查询时都需要动态执行 SQL 语句;而物化视图会实际存储查询结果,就像一个物理表一样。物化视图的数据会定期或在特定条件下刷新,以保证与基表数据的一致性。
物化视图的用途
物化视图在数据库中有多种重要用途,具体如下:
- 提高查询性能:对于复杂的查询,尤其是涉及多表连接、聚合函数的查询,使用物化视图可以显著提高查询速度,因为查询结果已经预先计算并存储好了。
- 减少资源消耗:由于物化视图减少了对基表的频繁查询,从而降低了数据库的 CPU、I/O 等资源消耗。
- 实现数据汇总:可以使用物化视图来预先计算和存储数据的汇总信息,如统计报表、聚合数据等。
- 支持数据仓库和 OLAP:在数据仓库环境中,物化视图经常被用于存储历史数据和聚合数据,以支持联机分析处理(OLAP)。
- 提供数据快照:物化视图可以提供某个时间点的数据快照,适用于需要历史数据对比的场景。
物化视图的创建
创建物化视图的基本语法如下:
CREATE MATERIALIZED VIEW mv_name
[BUILD IMMEDIATE | BUILD DEFERRED]
[REFRESH [FAST | COMPLETE | FORCE]
[ON DEMAND | ON COMMIT]
[START WITH date]
[NEXT date]
[WITH PRIMARY KEY | WITH ROWID]
[USING INDEX | USING NO INDEX]
[ENABLE | DISABLE QUERY REWRITE]
AS subquery;
下面对语法中的关键参数进行说明:
- BUILD IMMEDIATE | BUILD DEFERRED:指定创建物化视图时是否立即填充数据。BUILD IMMEDIATE 表示创建时立即填充数据(默认值);BUILD DEFERRED 表示创建时不填充数据,需要手动刷新后才有数据。
- REFRESH:指定物化视图的刷新方式和时间:
- FAST:只刷新自上次刷新以来发生变化的数据,需要基表上有物化视图日志支持。
- COMPLETE:完全重新生成整个物化视图。
- FORCE:优先使用 FAST 刷新,如果不可行则使用 COMPLETE 刷新(默认值)。
- ON DEMAND:手动刷新,需要执行 DBMS_MVIEW.REFRESH 过程(默认值)。
- ON COMMIT:在基表发生提交时自动刷新,要求物化视图必须基于单个表,且刷新方式必须为 FAST。
- WITH PRIMARY KEY | WITH ROWID:指定刷新时使用的标识符。WITH PRIMARY KEY 使用主键(默认值);WITH ROWID 使用 ROWID,适用于没有主键的表,刷新性能更高。
- ENABLE | DISABLE QUERY REWRITE:启用或禁用查询重写。启用后,Oracle 会自动将符合条件的查询重定向到物化视图上执行,以提高查询性能。
下面是创建物化视图的示例:
-- 创建一个简单的物化视图,每天晚上10点刷新
CREATE MATERIALIZED VIEW emp_salary_mv
BUILD IMMEDIATE
REFRESH COMPLETE
START WITH TO_DATE('2025-06-25 22:00:00', 'YYYY-MM-DD HH24:MI:SS')
NEXT SYSDATE + 1
AS
SELECT department_id, AVG(salary) AS avg_salary, COUNT(*) AS emp_count
FROM employees
GROUP BY department_id;
-- 创建一个快速刷新的物化视图,在基表提交时自动刷新
CREATE MATERIALIZED VIEW log ON employees
WITH PRIMARY KEY;
CREATE MATERIALIZED VIEW dept_emp_mv
BUILD IMMEDIATE
REFRESH FAST
ON COMMIT
WITH PRIMARY KEY
AS
SELECT d.department_id, d.department_name, COUNT(e.employee_id) AS emp_count
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
物化视图的刷新
刷新物化视图有多种方式,具体如下:
- 自动刷新:通过 ON COMMIT 或定期调度(如 START WITH 和 NEXT 参数)实现自动刷新。
- 手动刷新:使用 DBMS_MVIEW.REFRESH 过程手动刷新物化视图,示例如下:
-- 手动刷新单个物化视图
EXEC DBMS_MVIEW.REFRESH('emp_salary_mv');
-- 手动刷新多个物化视图
EXEC DBMS_MVIEW.REFRESH('emp_salary_mv, dept_emp_mv');
-- 快速刷新物化视图
EXEC DBMS_MVIEW.REFRESH('dept_emp_mv', 'F');
-- 完全刷新物化视图
EXEC DBMS_MVIEW.REFRESH('emp_salary_mv', 'C');
物化视图的查询
查询物化视图的方式与查询普通表相同,例如:
SELECT * FROM emp_salary_mv;
SELECT department_name, emp_count FROM dept_emp_mv;
物化视图的管理
- 查看物化视图信息:可以通过查询数据字典视图来获取物化视图的信息,例如:
-- 查看所有物化视图
SELECT * FROM USER_MVIEWS;
-- 查看物化视图的刷新状态
SELECT * FROM USER_MVIEW_REFRESH_TIMES;
- 修改物化视图:使用 ALTER MATERIALIZED VIEW 语句修改物化视图的属性,例如:
-- 修改物化视图的刷新方式
ALTER MATERIALIZED VIEW emp_salary_mv
REFRESH COMPLETE
START WITH SYSDATE + 1/24
NEXT SYSDATE + 1;
-- 启用查询重写
ALTER MATERIALIZED VIEW emp_salary_mv
ENABLE QUERY REWRITE;
- 删除物化视图:使用 DROP MATERIALIZED VIEW 语句删除物化视图,例如:
DROP MATERIALIZED VIEW emp_salary_mv;
物化视图的注意事项
在使用物化视图时,有一些注意事项需要了解:
- 刷新开销:物化视图的刷新会带来一定的开销,尤其是 COMPLETE 刷新,可能会影响数据库性能。因此,需要合理安排刷新频率。
- 数据一致性:物化视图的数据是定期刷新的,因此在两次刷新之间,物化视图的数据可能与基表数据不一致。如果需要实时数据,应使用普通视图。
- 查询重写:启用查询重写后,Oracle 优化器会自动选择使用物化视图,但需要满足一定的条件,如查询语句与物化视图的定义完全匹配。
- 空间占用:物化视图会占用额外的磁盘空间,因为它存储了实际的数据。
- 依赖关系:物化视图依赖于基表,如果基表结构发生变化,可能需要重建物化视图。
通过合理使用物化视图,可以显著提高复杂查询的性能,降低数据库负载,适用于数据仓库、报表系统等对查询性能要求较高的场景。