在近期项目中,我们遇到了一个常见难题——报表查询的SQL执行效率极低,令人十分困扰。原因主要是多表关联查询导致数据量庞大,查询速度自然变得缓慢。最终我们采用了Oracle物化视图方案,成功实现了查询加速,效果显著。

1、物化视图概述
物化视图,本质上是一张物理表,用于存储某个查询的结果集。它可以是远程数据的本地副本,也可以是基于数据表汇总生成的聚合表。Oracle通过内部机制定期更新物化视图,从而将原本耗时的大表连接操作预先计算好,查询时直接读取结果,显著提升SQL性能。
创建物化视图时,有几个关键参数需要关注:
(1) 创建方式:Build Immediate 和 Build Deferred。前者在创建时立即生成数据,后者则等到首次使用时才生成数据。默认值为Build Immediate。
(2) 查询重写: Enable Query Rewrite 和 Disable Query Rewrite。启用查询重写后,Oracle在对基表执行查询时,会自动判断是否可以通过物化视图直接获取结果,从而避免复杂的聚合或连接操作。默认值为Disable Query Rewrite。
(3) 刷新: 这是物化视图的核心机制。当基表数据发生DML操作后,物化视图需要决定何时以及如何与基表保持同步。
刷新的模式有两种:
- On Demand:按需刷新。可以手动调用DBMS_MVIEW.REFRESH,也可以通过定时任务(JOB)触发。
- On Commit:基表提交事务时自动刷新。
刷新的方法有四种:
- Fast:增量刷新,只处理自上次刷新以来的变更数据。
- Complete:全量刷新,重新计算整个物化视图。
- Force:优先尝试快速刷新,若无法执行则回退到全量方式。
- Never:不进行任何刷新操作。
默认值为Force On Demand。
快速刷新机制依赖于物化视图日志,并且一个日志可以支持多个物化视图的增量刷新。不过本次项目需求直接采用了Complete刷新,因此未使用日志方案。
了解基本概念后,接下来直接进入实战环节。
2、功能实现
(1) 创建物化视图
采用On Demand模式 + Complete刷新,创建时立即生成数据,之后每天凌晨1点进行全量刷新。
CREATE MATERIALIZED VIEW MV_DATAREFRESH COMPLETE ON DEMAND --第一次刷新时间 START WITH SYSDATE --每天凌晨一点刷新 NEXT TRUNC(sysdate+1)+1/24 WITH PRIMARY KEY DISABLE QUERY REWRITE AS <查询sql>
(2) Java后台通过MyBatis获取报表数据
(3) 获取物化视图上次刷新时间
(4) 添加手动刷新功能
Java无法直接刷新物化视图,因此我们采用间接方式——在数据库中创建存储过程,由存储过程执行刷新动作。
包中追加存储过程方法
CREATE OR REPLACE
PACKAGE "REPORT" AS
PROCEDURE P_MV_DATA;
END;
创建存储过程
CREATE OR REPLACE
package body REPORT is
PROCEDURE P_MV_DATA
IS
BEGIN
DBMS_MVIEW.REFRESH (
list => 'MV_DATA',
Method => 'COMPLETE',
refresh_after_errors => True
);
END;
end;
然后在mapper.xml中调用这个存储过程:
(5) 删除物化视图
DROP MATERIALIZED VIEW MV_DATA;
(6) 创建索引
create index IDX_MV_DATA_ID on MV_DATA(id);
3、总结
以上就是整个方案的实现过程。物化视图是一个十分实用的工具,尤其适用于多表关联、数据量大且查询频率高的场景。本次项目选择了Complete刷新方式,虽然每次刷新会全量重建数据,但胜在实现简单、维护成本低。如果数据变更频繁且业务对实时性要求较高,可以考虑切换到快速刷新配合物化视图日志的模式,以进一步提升刷新效率。通过合理运用Oracle物化视图,能够有效优化多表查询性能,提升报表系统的响应速度。
