"太多的声明' SUBSTR'匹配这个电话"同时刷新物化视图

时间:2014-11-18 17:09:16

标签: oracle materialized-views

我将物化视图设置为REFRESH FAST ON COMMIT。源表中有4个BLOB列,我将转换为VARCHAR2作为MV的一部分:

CREATE MATERIALIZED VIEW Employee_MV
REFRESH FAST ON COMMIT
WITH PRIMARY KEY
AS
SELECT UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR (History, 2000, 1)), //BLOB column
       <3 more blob columns with similar conversions>,
       <misc columns from different tables>,
       <rowid columns for tables for REFRESH FAST to work>
FROM   <list of tables with JOINs>

如果在使用BLOB列在参与表中插入行时刷新MV - 无论是通过ON COMMIT还是ON DEMAND - 它都会出错,并显示以下消息:

ORA-12008: error in materialized view refresh path
ORA-06553: PLS-307: too many declarations of 'SUBSTR' match this call
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2545
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2751
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2720
ORA-06512: at line 1

让我感到困惑的是,错误发生在&#34; DBMS_LOB.SUBSTR&#34;呼叫。 (这是我在这个MV中使用SUBSTR的唯一地方,如果我删除BLOB转换,MV会刷新而不会出错。)

这是否意味着Oracle无法解析为正确的重载版本(CLOB,BLOB和BFILE各有一个SUBSTR)?但这没有任何意义,因为如果我单独运行这个MV的SELECT查询,它运行就好了。

我在这里缺少什么?

更新:我尝试使用REFRESH COMPLETE选项刷新MV,并使用相同的数据。所以现在我的情况是SUBSTR()仅在FAST刷新时失败,但适用于COMPLETE刷新。

更新2:当前的Oracle版本是11.1.0.7。我尝试在Oracle 10.2.0.4(不同的环境)中运行相同的MV。 MV完成了FAST REFRESH,没有任何问题。

因此,DBMS_LOB.SUBSTR处理BLOB存在一些问题:

  1. COMPLETE刷新中运行的内容在FAST刷新中无法正常运行。
  2. Oracle 10.2.0.4中运行的内容并不在11.1.0.7中运行。
  3. 如何进一步解决此问题?

    更新3:我刚刚运行了一些测试来检查BLOB列中是否存在NULL这样的行为 - 事实证明即使使用非空值,MV FAST REFRESH也会失败并出现相同的错误。我已相应更新了问题。

2 个答案:

答案 0 :(得分:1)

如果Oracle不允许你运行这么多次&#34; substr&#34;在那个MV中的功能 - 做一些欺骗他的技巧;) 你可以做这个&#34; substr&#34;通过使用虚拟列来快速刷新之前调用:

alter table YOUR_TABLE add History_substr as (DBMS_LOB.SUBSTR (History,2000, 1)) virtual;

在这里做其他&#34; 3个具有类似转换的blob列&#34;如上所述,然后您可以使用您的虚拟列:

CREATE MATERIALIZED VIEW Employee_MV
REFRESH FAST ON COMMIT
WITH PRIMARY KEY
AS
SELECT UTL_RAW.CAST_TO_VARCHAR2(History_substr), //BLOB column
       <3 more blob columns with similar conversions>,
       <misc columns from different tables>,
       <rowid columns for tables for REFRESH FAST to work>
FROM   <list of tables with JOINs>

答案 1 :(得分:0)

FAST和COMPLETE刷新之间的区别之一是刷新过程执行更复杂的“解析”,以便根据已更改的源表等快速刷新特定列中的值。 ROWID必须作为mview列的一部分包含在内的原因之一,因此它可以找到正确的行来更改列值。

我认为版本10和版本11之间的区别之一是,当您将长表达式创建为列时,版本10将为列提供SYSxxxxxxxx名称,而版本11则尝试将表达式保留为列名称。 / p>

您的查询类似于:

SELECT UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR (History, 2000, 1)),
       UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR (AnotherCol, 2000, 1)),
       ...

有可能(无法测试,所以我不完全确定)当列名称是如此长的表达式时,您实际看到的是在处理有关mview的元数据时出错。

您是否看过创建的mview的列名?它们是长而复杂的表达吗?如果是,那么我建议尝试使用列别名:

SELECT UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR (History, 2000, 1)) AS col1,
       UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR (AnotherCol, 2000, 1)) AS col2,
       ...

(好吧,你可以使用比col1更有意义的名字,col2当然; - )