【问题标题】:ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized viewORA-12054: 无法为实体化视图设置 ON COMMIT 刷新属性
【发布时间】:2016-12-24 00:10:40
【问题描述】:

我在为我们的聚合创建物化视图时遇到问题。如果源表上发生 DML,则物化视图应自动刷新并显示更新后的结果。这个想法是存储聚合结果并直接获取数字而不是进行查询,我基本上想看看这是否符合我们的目标。我们的表每天将有多达 300 万次插入。

根据链接Example 8-3 Example 3: Creating a Materialized View 我做了:

CREATE MATERIALIZED VIEW LOG ON table WITH SEQUENCE, ROWID
(SUBJECTID)
INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW ih_data_aggregated_view
PARALLEL 
BUILD IMMEDIATE 
REFRESH FAST ON COMMIT
AS
SELECT SUBJECTID ,count(*)as totalcount ,avg(price)as avgprice,sum(price) as totalprice
FROM table  
WHERE SUBJECTID='xxxxx'  GROUP by SUBJECTID;

但这会得到:

java.sql.SQLException: SQLException: ORA-12054: 无法为物化视图设置 ON COMMIT 刷新属性

【问题讨论】:

  • 你看过the restrictions吗?
  • “对于每个聚合,例如 AVG(expr),必须存在相应的 COUNT(expr)。”。您应该尝试将count(*) 更改为count(price)

标签: sql oracle oracle11g materialized-views


【解决方案1】:

文档包括general restrictions on materialised viewmaterialised view with aggregates

虽然处理这些列表很有启发性,但您可以通过检查来自the dbms_mview.explain_mview procedure 的结果来了解现有或潜在的物化视图是否可以快速刷新:

set serveroutput on
declare
  msg_array SYS.ExplainMVArrayType;
begin
  dbms_mview.explain_mview (q'[
SELECT SUBJECTID ,count(*)as totalcount ,avg(price)as avgprice,sum(price) as totalprice
FROM your_table
WHERE SUBJECTID='xxxxx'
GROUP by SUBJECTID
]',
     msg_array);
   for i in msg_array.first..msg_array.last loop
     dbms_output.put_line(rpad(msg_array(i).capability_name, 30)
       ||' '|| msg_array(i).possible
       ||' '|| msg_array(i).msgtxt);
  end loop;
end;
/

...
REFRESH_FAST                   F 
...
REFRESH_FAST_AFTER_INSERT      F agg(expr) requires correspondng COUNT(expr) function
REFRESH_FAST_AFTER_ONETAB_DML  F SUM(expr) without COUNT(expr)
REFRESH_FAST_AFTER_ONETAB_DML  F see the reason why REFRESH_FAST_AFTER_INSERT is disabled
REFRESH_FAST_AFTER_ANY_DML     F see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled
REFRESH_FAST_PCT               F PCT is not possible on any of the detail tables in the materialized view
...

正如@vercelli 提到的,以及REFRESH_FAST_AFTER_INSERT 消息所暗示的,您需要将count(*) 更改为count(price)。但这还不是全部。如果你只是改变,你会看到:

REFRESH_FAST                   F 
...
REFRESH_FAST_AFTER_INSERT      F mv log does not have all necessary columns
REFRESH_FAST_AFTER_ONETAB_DML  F see the reason why REFRESH_FAST_AFTER_INSERT is disabled
REFRESH_FAST_AFTER_ONETAB_DML  F COUNT(*) is not present in the select list
REFRESH_FAST_AFTER_ANY_DML     F see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled

您的物化视图日志必须包含您正在聚合的列:

CREATE MATERIALIZED VIEW LOG ON your_table WITH SEQUENCE, ROWID
(SUBJECTID,PRICE)
INCLUDING NEW VALUES;

Materialized view LOG created.

CREATE MATERIALIZED VIEW ih_data_aggregated_view
PARALLEL 
BUILD IMMEDIATE 
REFRESH FAST ON COMMIT
AS
SELECT SUBJECTID ,count(price)as totalcount ,avg(price)as avgprice,sum(price) as totalprice
FROM your_table
WHERE SUBJECTID='xxxxx'
GROUP by SUBJECTID;

Materialized view IH_DATA_AGGREGATED_VIEW created.

仍会报告缺少的count(*),但由于这是针对单个表的,因此不会阻止快速刷新。值得注意的是,如果您的price 列可以为空,那么count(price)count(*) 可能会给出不同的结果;如果是这种情况,您可能希望将这两个计数都作为列在您的 MV 中。

【讨论】:

  • 嗨,Alex 感谢您提供详细的答案。我仍然面临同样的问题。 REFRESH_FAST_AFTER_INSERT 功能说得更好:mv 日志没有所有必要的列。当我执行您的过程时,它向我显示 REFRESH_FAST_AFTER_INSERT F mv 日志没有所有必要的列。我使用您提到的查询创建了视图。Oracle 数据库 12c 企业版发布12.1.0.1.0 - 64 位生产
  • @MrWayne - 你重新创建了 MV 日志以包含价格列?
  • 是的,我做到了。我遵循的确切命令在 LOG CREATE MATERIALIZED VIEW LOG ON PR_DATA_IH_FACT_MILLION WITH SEQUENCE、ROWID (SUBJECTID、PRICE) 包括新值上创建 MV;
  • 错误报告:SQL 错误:ORA-12033:无法使用“TE_6051”上的物化视图日志中的过滤列。“PR_DATA_IH_FACT_MILLION”12033。0000 -“无法使用 \ 上的物化视图日志中的过滤列” %s\".\"%s\"" *原因:物化视图日志没有记录过滤列,或者与过滤列关联的时间戳比上次刷新时间更新。 *操作:在下一次快速刷新之前需要完全刷新。如果需要,将过滤列添加到物化视图日志。
  • 那么这表明你的 MV 引用了你没有提到的其他列——不仅仅是 subjectid 和 price。您在 MV 查询中引用的任何列都必须包含在 MV 日志中。
猜你喜欢
  • 2020-05-10
  • 2016-11-22
  • 1970-01-01
  • 2016-01-22
  • 2022-08-15
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2012-06-12
相关资源
最近更新 更多