【问题标题】:Can't set the ON COMMIT refresh attribute when creating a materialized view containing partial primary key in Oracle在 Oracle 中创建包含部分主键的物化视图时无法设置 ON COMMIT 刷新属性
【发布时间】:2016-01-22 10:38:51
【问题描述】:

我需要将作为主键一部分的列的唯一值从表中提取到物化视图中。如果使用“刷新完成”,我可以创建物化视图,但在尝试使用“提交时快速刷新”时没有运气。谁能指出我是否遗漏了什么或 Oracle 不支持此类操作。

示例输出如下所示。谢谢。

SQL> create table TEST( col1 number, col2 number, col3 varchar(32), CONSTRAINT test_pk Primary Key (col1, col2));

Table created.

SQL> create materialized view test_mv build immediate refresh fast on commit as select distinct col2 from test;
create materialized view test_mv build immediate refresh fast on commit as select distinct col2 from test
                                                                                                     *
ERROR at line 1:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view


SQL> create materialized view test_mv build immediate refresh complete as select distinct col2 from test;

Materialized view created.

SQL> drop materialized view test_mv;

Materialized view dropped.

SQL> create materialized view log on test;

Materialized view log created.

SQL> create materialized view test_mv build immediate refresh fast on commit as select distinct col2 from test;
create materialized view test_mv build immediate refresh fast on commit as select distinct col2 from test
                                                                                                     *
ERROR at line 1:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view

【问题讨论】:

    标签: oracle primary-key materialized-views


    【解决方案1】:

    快速刷新视图很挑剔。此解决方案需要具有特定属性的物化视图日志,以及具有一些额外功能和不同语法的物化视图。

    似乎不支持单独的DISTINCT。但是有aggregate materialized views 支持GROUP BY。如果该物化视图是用ENABLE QUERY REWRITE 创建的,Oracle 可以在DISTINCT 查询中使用它。还有一个额外的COUNT(*),因为“COUNT(*) 必须始终存在以保证所有类型的快速刷新。”

    创建表、物化视图日志和物化视图。

    create table test(col1 number, col2 number, col3 varchar(32)
      ,constraint test_pk primary key (col1, col2));
    create materialized view log on test with rowid (col2) including new values;
    create materialized view test_mv
      build immediate
      refresh fast on commit
      enable query rewrite as
      select col2, count(*) total from test group by col2;
    

    查询可以使用物化视图。

    这些解释计划表明物化视图适用于 GROUP BYDISTINCT 查询。

    explain plan for select col2 from test group by col2;
    select * from table(dbms_xplan.display);
    
    explain plan for select distinct col2 from test;
    select * from table(dbms_xplan.display);
    
    
    Plan hash value: 1627509066
    
    ----------------------------------------------------------------------------------------
    | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
    ----------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |         |     1 |    13 |     2   (0)| 00:00:01 |
    |   1 |  MAT_VIEW REWRITE ACCESS FULL| TEST_MV |     1 |    13 |     2   (0)| 00:00:01 |
    ----------------------------------------------------------------------------------------
    

    【讨论】:

    • 由于我使用的是 Oracle SE,我没有查询重写支持,但我仍然可以在没有“启用查询重写”子句的情况下创建物化视图。缺点是在您的答案中运行两个查询时会导致全表访问。无论如何,我现在不担心这个,相信一旦我迁移到 Oracle EE,问题就会消失。我现在感到困惑的是在基表测试中更新 col2 之后,mv 没有得到更新/刷新。在基表中插入新记录后,mv 将得到更新。还有其他我错过/误解的事情吗?
    • 这是我错过的东西 - 聚合物化视图应包含 COUNT(*)。修改后的示例效果更好。
    • 工作就像一个魅力! mv 更新成功。太好了!
    【解决方案2】:

    您观点的主要问题是 DISTINCT 子句。提交时快速刷新对底层查询非常敏感。物化视图必须满足许多规则才能支持快速刷新。 DISTINCT 阻止它。

    您可以使用DBMS_MVIEW.EXPLAIN_MVIEW 过程检查物化视图的功能:

    DECLARE
        result SYS.EXPLAINMVARRAYTYPE := SYS.EXPLAINMVARRAYTYPE();
    BEGIN
        DBMS_MVIEW.EXPLAIN_MVIEW('TEST_MV', result);
    
        FOR i IN result.FIRST..result.LAST LOOP
            DBMS_OUTPUT.PUT_LINE(result(i).CAPABILITY_NAME || ': ' || CASE WHEN result(i).POSSIBLE = 'T' THEN 'Yes' ELSE 'No' || CASE WHEN result(i).RELATED_TEXT IS NOT NULL THEN ' because of ' || result(i).RELATED_TEXT END || '; ' || result(i).MSGTXT END);
        END LOOP;
    END;
    

    您可以在文档http://docs.oracle.com/cd/B28359_01/server.111/b28313/basicmv.htm#i1007007中找到更多信息

    【讨论】:

    • 你是对的,它可以防止它发生。但是,奇怪的是,您可以使用GROUP BY 创建一个,Oracle 将能够将其用于DISTINCT 查询。详情见我的回答。
    猜你喜欢
    • 2020-05-10
    • 2016-12-24
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 2019-01-10
    相关资源
    最近更新 更多