定位导致物化视图无法快速刷新的原因

物化视图的快速刷新采用了增量的机制,在刷新时,只针对基表上发生变化的数据进行刷新。因此快速刷新是物化视图刷新方式的首选。

但是快速刷新具有较多的约束,而且对于采用ON COMMIT模式进行快速刷新的物化视图更是如此。对于包含聚集和包含连接的物化视图的快速刷新机制并不相同,而且对于多层嵌套的物化视图的快速刷新更是有额外的要求。

如此多的限制一般很难记全,当建立物化视图失败时,Oracle给出的错误信息又过于简单,有时无法使你准确定位到问题的原因。

Oracle提供的DBMS_MVIEW.EXPLAIN_MVIEW过程可以帮助你快速定位问题的原因。下面通过一个例子来说明,如果通过这个过程来解决问题。

 


建立一个快速刷新的嵌套物化视图:

SQL> CREATE TABLE B (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> CREATE TABLE C (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));

表已创建。

SQL> CREATE TABLE A (ID NUMBER, BID NUMBER, CID NUMBER, NUM NUMBER,
  2  CONSTRAINT FK_A_B_BID FOREIGN KEY (BID) REFERENCES B(ID),
  3  CONSTRAINT FK_A_C_BID FOREIGN KEY (CID) REFERENCES C(ID));

表已创建。

SQL> INSERT INTO B SELECT ROWNUM, 'B'||ROWNUM FROM USER_TABLES WHERE ROWNUM <= 6;

已创建6行。

SQL> INSERT INTO C SELECT ROWNUM, 'C'||ROWNUM FROM USER_TABLES WHERE ROWNUM <= 4;

已创建4行。

SQL> INSERT INTO A SELECT ROWNUM, TRUNC((ROWNUM - 1)/2) + 1, TRUNC((ROWNUM - 1)/3) + 1, ROWNUM
  2  FROM USER_TABLES
  3  WHERE ROWNUM <= 12;

已创建12行。

SQL> COMMIT;

提交完成。

上面建立好基表,下面建立第一层物化视图。

SQL> CREATE MATERIALIZED VIEW LOG ON A WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW LOG ON B WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW LOG ON C WITH ROWID;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
  2  SELECT C.ID CID, C.NAME CNAME, B.ID BID, B.NAME BNAME, A.NUM,
  3  A.ROWID AROWID, B.ROWID BROWID, C.ROWID CROWID
  4  FROM A, B, C WHERE A.BID = B.ID AND A.CID = C.ID;

实体化视图已创建。

第一次物化视图已经建立成功,下面建立嵌套物化视图:

SQL> CREATE MATERIALIZED VIEW LOG ON MV_ABC WITH ROWID (BNAME, CNAME, NUM) INCLUDING NEW VALUES;

实体化视图日志已创建。

SQL> CREATE MATERIALIZED VIEW MV_MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
  2  SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
  3  GROUP BY CNAME, BNAME;
SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
                                                           *
ERROR 位于第 2 行:
ORA-12053: 这不是一个有效的嵌套实体化视图

错误出现了,不过错误的描述包含的信息量并不大。我们看看Oracle的文档上是如何描述这个错误的。

ORA-12053 this is not a valid nested materialized view

Cause: The list of objects in the FROM clause of the definition of this materialized view had some dependencies upon each other.

Action: Refer to the documentation to see which types of nesting are valid.

文档上的描述也是十分笼统的,并没有指出具体问题所在。

接下来,我们通过使用DBMS_MVIEW.EXPLAIN_MVIEW过程来定位错误。

使用EXPLAIN_MVIEW过程首先要建立MV_CAPABILITIES_TABLE表,建表的脚步是$ORACLE_HOME/rdbms/admin/utlxmv.sql。(EXPLAIN_MVIEW过程是两个过程的重载,一个输出到MV_CAPABILITIES_TABLE表,另一个以PL/SQL的VARRAY格式输出,为了简单起见,我们建立MV_CAPABILITIES_TABLE表)。

SQL> @?rdbmsadminutlxmv.sql

表已创建。

下面简单研究一下EXPLAIN_MVIEW过程。

DBMS_MVIEW.EXPLAIN_MVIEW(mv IN VARCHAR2, Statement_id IN VARCHAR2:= NULL);

该过程可以输入已经存在的物化视图名称(或USER_NAME.MV_NAME),也可输入建立物化视图的查询语句。另外一个参数STATEMENT_ID输入一个语句ID,为了标识出表中对应的记录。

SQL> BEGIN
  2  DBMS_MVIEW.EXPLAIN_MVIEW('SELECT CNAME, BNAME, COUNT(*) COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
  3  GROUP BY CNAME, BNAME', 'MV_MV_ABC');
  4  END;
  5  /

PL/SQL 过程已成功完成。

SQL> SELECT CAPABILITY_NAME, RELATED_TEXT, MSGTXT FROM MV_CAPABILITIES_TABLE
  2  WHERE STATEMENT_ID = 'MV_MV_ABC' AND POSSIBLE = 'N' AND CAPABILITY_NAME NOT LIKE '%PCT%';

CAPABILITY_NAME                RELATED_TEXT    MSGTXT
------------------------------ --------------- --------------------------------------------------
REFRESH_FAST_AFTER_ONETAB_DML  SUM_NUM         使用 SUM(expr) 时, 未提供 COUNT(expr)
REFRESH_FAST_AFTER_ANY_DML     YANGTK.MV_ABC   mv 日志没有序列号
REFRESH_FAST_AFTER_ANY_DML                     查看禁用 REFRESH_FAST_AFTER_ONETAB_DML 的原因

根据上面的信息,已经可以确定问题的原因了,对于聚集物化视图,使用了SUM(COLUMN),但是没有包括COUNT(COLUMN)。

修改物化视图,重新建立:

SQL> CREATE MATERIALIZED VIEW MV_MV_ABC REFRESH FAST ON COMMIT ENABLE QUERY REWRITE AS
  2  SELECT CNAME, BNAME, COUNT(*) COUNT, COUNT(NUM) NUM_COUNT, SUM(NUM) SUM_NUM FROM MV_ABC
  3  GROUP BY CNAME, BNAME;

实体化视图已创建。

<think>嗯,用户遇到了ORA-12057错误,物化视图在修改后没有自动刷新,需要进行完全刷新。首先,我需要回忆一下ORA-12057的具体原因。根据之前的知识,这个错误通常与物化视图快速刷新(FAST REFRESH)有关,尤其是当基表的物化视图日志(MV Log)不完整或不符合要求时。 用户提到物化视图名为STUDY.CUSTOMER_ORDER_SUMMARY,可能需要检查这个物化视图的基表是否有正确的物化视图日志。首先,物化视图日志必须包含所有在物化视图查询中引用的字段,特别是聚合函数或连接条件中用到的列。如果日志缺少某些列,快速刷新就会失败,导致ORA-12057错误。 接下来,用户的问题可能涉及物化视图日志的类型是否正确。例如,如果基表没有主键,必须使用ROWID类型的日志,否则快速刷新可能无法进行。需要确认日志的创建语句是否包含正确的WITH子句(如ROWID或PRIMARY KEY)。 另外,权限问题也可能导致错误。物化视图的所有者需要有基表的SELECT权限,以及QUERY REWRITE等权限。如果权限不足,即使日志正确,刷新也会失败。 还有可能是物化视图本身的定义不符合快速刷新的要求。例如,如果物化视图中使用了某些不支持快速刷新的操作,如UNION、MINUS或特定的分析函数,那么即使有日志,也无法进行快速刷新,必须使用完全刷新。 用户还提到需要了解如何进行完全刷新。完全刷新会重新执行物化视图的查询,替换所有数据,但这可能效率较低,尤其是在大数据量的情况下。不过,在快速刷新不可行时,完全刷新是解决问题的临时方法。 需要检查物化视图的状态,确认最后一次刷新是否成功,以及刷新方式是否为FAST。如果系统尝试自动刷新但失败,可能需要手动执行完全刷新来恢复,但关键还是要解决导致快速刷新失败的根本原因。 此外,还需要查看Oracle的告警日志,查找ORA-12057错误的详细信息,可能包含更具体的线索,比如哪个基表的日志有问题,或者哪个列缺失。手动执行快速刷新并捕获错误信息也是一个好方法,可以更直接地定位问题。 总结起来,解决步骤可能包括: 1. 检查物化视图日志是否包含所有必要字段。 2. 确认日志类型(ROWID或PRIMARY KEY)是否正确。 3. 验证物化视图的查询是否符合快速刷新要求。 4. 检查权限是否足够。 5. 查看错误日志获取详细信息。 6. 必要时重建日志或物化视图,并进行完全刷新作为临时解决方案。 需要一步步引导用户进行排查,确保每个可能的原因都被覆盖,并提供具体的SQL命令示例,帮助用户实际操作。同时,要区分完全刷新快速刷新的使用场景,避免用户混淆。</think>### ORA-12057 错误分析与解决方案 #### **1. ORA-12057 错误原因** 错误 `ORA-12057: materialized view log on "<基表名>" does not have all necessary columns` 表示物化视图的**快速刷新(FAST REFRESH)依赖的物化视图日志(Materialized View Log)不完整**,具体原因包括: - **基表日志缺失关键字段**:物化视图查询中引用的基表字段未包含在日志中。 - **日志类型不匹配**:基表无主键时未使用 `ROWID` 类型日志,或未正确声明 `PRIMARY KEY`。 - **物化视图定义包含不支持 FAST 刷新的操作**:如复杂聚合函数、外连接过滤条件等[^1]。 --- #### **2. 针对 `STUDY.CUSTOMER_ORDER_SUMMARY` 的排查步骤** ##### **步骤 1:验证物化视图日志完整性** 检查基表(例如 `CUSTOMER_ORDERS`)的日志是否包含物化视图查询中所有引用的字段: ```sql -- 查询物化视图日志字段 SELECT column_name, log_include FROM user_mview_log_columns WHERE log_owner = 'STUDY' AND master = 'CUSTOMER_ORDERS'; -- 替换为实际基表名 -- 查询物化视图日志类型 SELECT log_table, log_owner, rowids, primary_key FROM user_mview_logs WHERE master = 'CUSTOMER_ORDERS'; ``` - **关键验证点**: - 若基表无主键,`rowids` 必须为 `YES`。 - 物化视图查询中的 `SELECT` 列(如聚合字段、连接字段)需全部在日志字段中列出。 --- ##### **步骤 2:检查物化视图定义兼容性** 确认 `CUSTOMER_ORDER_SUMMARY` 的查询是否符合 FAST 刷新要求: ```sql -- 查询物化视图定义 SELECT query FROM user_mviews WHERE mview_name = 'CUSTOMER_ORDER_SUMMARY'; ``` - **不兼容操作示例**: - 使用 `UNION`、`MINUS`(仅允许 `UNION ALL`) - 使用 `RANK()`、`DENSE_RANK()` 等非标准聚合函数 - 外连接(如 `LEFT JOIN`)后附加复杂过滤条件 --- ##### **步骤 3:手动触发 FAST 刷新并捕获错误** 通过手动刷新获取详细错误信息: ```sql BEGIN DBMS_MVIEW.REFRESH('STUDY.CUSTOMER_ORDER_SUMMARY', method => 'F'); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('错误代码: ' || SQLCODE || ', 错误信息: ' || SQLERRM); END; ``` - **输出示例**: `ORA-12057: materialized view log on "CUSTOMER_ORDERS" does not have all necessary columns` 明确指向缺失字段的基表。 --- #### **3. 解决方案** ##### **方案 1:修复物化视图日志** - **重建日志(包含所有必要字段)**: ```sql -- 删除旧日志 DROP MATERIALIZED VIEW LOG ON STUDY.CUSTOMER_ORDERS; -- 创建新日志(假设基表无主键) CREATE MATERIALIZED VIEW LOG ON STUDY.CUSTOMER_ORDERS WITH ROWID (order_id, customer_id, order_amount, order_date) -- 包含所有物化视图引用的字段 INCLUDING NEW VALUES; ``` - **关键点**: - 若基表有主键,使用 `PRIMARY KEY` 替代 `ROWID` 以减少存储开销[^2]。 - `INCLUDING NEW VALUES` 记录新旧值差异,支持增量刷新。 ##### **方案 2:调整物化视图定义** 若查询包含不支持 FAST 刷新的操作,需重写定义。例如,避免使用 `RANK()`: ```sql -- 原定义(不支持 FAST 刷新) CREATE MATERIALIZED VIEW STUDY.CUSTOMER_ORDER_SUMMARY REFRESH FAST ON COMMIT AS SELECT customer_id, RANK() OVER (ORDER BY SUM(order_amount) DESC) AS rank FROM CUSTOMER_ORDERS GROUP BY customer_id; -- 修改为仅使用 SUM(支持 FAST 刷新) CREATE MATERIALIZED VIEW STUDY.CUSTOMER_ORDER_SUMMARY REFRESH FAST ON COMMIT AS SELECT customer_id, SUM(order_amount) AS total_amount FROM CUSTOMER_ORDERS GROUP BY customer_id; ``` ##### **方案 3:执行完全刷新(临时修复)** 若需立即恢复数据一致性,执行完全刷新: ```sql BEGIN DBMS_MVIEW.REFRESH('STUDY.CUSTOMER_ORDER_SUMMARY', method => 'C'); END; ``` - **代价**:完全刷新会重新执行全量查询,可能耗时较长。 - **建议**:修复日志后切换回 `FAST` 刷新。 --- #### **4. 完全刷新与 FAST 刷新对比** | 特性 | FAST 刷新 | 完全刷新 | |--------------------|-------------------------------|--------------------------| | **速度** | 增量更新,速度快 | 全量替换,速度慢 | | **资源占用** | 低 | 高 | | **适用场景** | 频繁小量数据变更 | 首次构建或结构变更后 | | **日志依赖** | 必须正确配置基表日志 | 无需日志 | --- #### **5. 预防措施** 1. **设计阶段验证**: - 使用 `DBMS_MVIEW.EXPLAIN_MVIEW` 分析物化视图是否支持 FAST 刷新: ```sql EXEC DBMS_MVIEW.EXPLAIN_MVIEW('STUDY.CUSTOMER_ORDER_SUMMARY'); SELECT msg FROM mv_capabilities_table WHERE capability_name = 'REFRESH_FAST'; ``` 2. **监控日志字段变更**: - 基表结构变更(如新增字段)后,需重建物化视图日志。 3. **定期检查刷新状态**: ```sql SELECT mview_name, last_refresh_type, staleness FROM user_mviews WHERE mview_name = 'CUSTOMER_ORDER_SUMMARY'; ``` --- ### 相关问题 1. 如何判断物化视图是否需要完全刷新? 2. 物化视图日志的 `INCLUDING NEW VALUES` 参数对性能有何影响? 3. 如何处理因基表分区变更导致的 FAST 刷新失败? --- **引用说明** [^1]: Oracle 官方文档指出,FAST 刷新要求物化视图查询符合特定语法限制。 [^2]: 使用 `PRIMARY KEY` 日志可减少存储空间占用,但需基表主键稳定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值