使用实体化视图跟踪最新版本的记录

Use a Materialized View to track latest versions of records

我们有一个高度(也许超过?)标准化的 table 来跟踪版本值。它只是插入,没有更新。

示例数据:

"ID"    "Version"   "Value"
1       0           "A_1"
2       0           "B_1"
1       1           "A_2"
3       0           "C_1"

我们经常 运行 查询以仅提取每个 ID 的最新值。当我们达到数百万行时,我们开始遇到性能问题。我已经能够使用实体化视图进行原型改进,但无法以自我刷新的方式创建它们 "ON COMMIT"

到目前为止我得到的是这个(修改如下)

CREATE MATERIALIZED VIEW TABLE_LATEST 
    BUILD IMMEDIATE
    REFRESH FAST 
    ON COMMIT AS

SELECT  T.ID
       ,T.LAST_VERSION
FROM (
    SELECT  ID
           ,MAX(VERSION) OVER (PARTITION BY ID) LAST_VERSION
    FROM    TABLE
) T
GROUP BY T.ID, T.LAST_VERSION;

现在正在修改,由于反馈:

CREATE MATERIALIZED VIEW TABLE_LATEST 
    BUILD IMMEDIATE
    REFRESH FAST 
    ON COMMIT AS

SELECT  ID
       ,MAX(VERSION)
FROM    TABLE
GROUP BY T.ID;

失败:

ORA-12033: cannot use filter columns from materialized view log on "SCHEMA"."TABLE"

*Cause:    The materialized view log either did not have filter columns
           logged, or the timestamp associated with the filter columns was
           more recent than the last refresh time.

*Action:   A complete refresh is required before the next fast refresh.
           Add filter columns to the materialized view log, if required.

如果我将 Refresh 更改为 Force 并删除 On Commit,它只会 'work'。我不知道这是否属于实体化视图的 'No Analytics' 规则,或者我是否一开始就错误地创建了日志?

CREATE MATERIALIZED VIEW LOG ON TABLE
LOGGING 
WITH SEQUENCE, ROWID, (VALUE) 
INCLUDING NEW VALUES;

Table 架构:

CREATE TABLE "TABLE"
(
  ID NUMBER(10, 0) NOT NULL 
, VERSION NUMBER(10, 0) NOT NULL 
, VALUE VARCHAR2(4000 CHAR) 
, CONSTRAINT MASTERRECORDFIELDVALUES_PK PRIMARY KEY 
  (
    ID
  , VERSION 
  )
  USING INDEX 
  (
      CREATE UNIQUE INDEX TABLE_PK ON TABLE(ID ASC, VERSION ASC) 
      LOGGING 
      ...
  )
  ENABLE 
) 
LOGGING 

我走在正确的轨道上吗?是否有更好的方法来预计算最新版本?还是我只需要拨入“日志和查看”设置?

对不起,我不能马上给你答复。原因之一可能是使用了 MV 不支持的分析函数。要分析问题,您需要查看实体化视图的功能。

DECLARE
  -- Local variables here
  --
  v_sql VARCHAR2(32000) := 'SELECT  T.ID
                                   ,T.LAST_VERSION
                            FROM (SELECT  ID
                                         ,MAX(VERSION) OVER (PARTITION BY ID) LAST_VERSION    
                                  FROM    TABLE) T
                                  GROUP BY T.ID
                                          ,T.LAST_VERSION';

   v_msg_arrray SYS.EXPLAINMVARRAYTYPE;
   msg SYS.ExplainMVMessage;
BEGIN
  -- Test statements here
   dbms_mview.explain_mview(mv => v_sql, msg_array => v_msg_arrray);



  FOR i IN v_msg_arrray.FIRST..v_msg_arrray.LAST LOOP
    msg := v_msg_arrray(i);
    DBMS_OUTPUT.put_line('MVOWNER:' || msg.MVOWNER);
    DBMS_OUTPUT.put_line('MVNAME:' || msg.MVNAME);
    DBMS_OUTPUT.put_line('CAPABILITY_NAME:' || msg.CAPABILITY_NAME);
    DBMS_OUTPUT.put_line('POSSIBLE:' || msg.POSSIBLE);
    DBMS_OUTPUT.put_line('RELATED_TEXT:' || msg.RELATED_TEXT);
    DBMS_OUTPUT.put_line('RELATED_NUM:' || msg.RELATED_NUM);
    DBMS_OUTPUT.put_line('MSGNO:' || msg.MSGNO);    
    DBMS_OUTPUT.put_line('MSGTXT:' || msg.MSGTXT);
    DBMS_OUTPUT.put_line('SEQ:' || msg.SEQ);
    DBMS_OUTPUT.put_line('----------------------------------------');
  END LOOP;

END;

顺便说一句:您可以编写更简单的查询:

SELECT t.id,
       MAX(t.version) AS last_version
FROM table t
GROUP BY t.id;

如果您不需要与最新版本关联的值,那么您可以简单地执行:

CREATE MATERIALIZED VIEW LOG ON t1 
LOGGING  
WITH SEQUENCE, ROWID, (val) 
INCLUDING NEW VALUES;

create materialized view t1_latest
refresh fast on commit
as
  select id,
         max(version) latest_version
  from   t1
  group by id;

可以找到此测试用例 over at Oracle LiveSQL


否则,您需要创建三个单独的 MV(因为您无法在涉及保持 dense_rank first/last 的提交时快速刷新实体化视图)- 根据 http://www.sqlsnippets.com/en/topic-12926.html - 就像这样:

主table上的物化视图日志:

CREATE MATERIALIZED VIEW LOG ON t1
LOGGING 
WITH SEQUENCE, ROWID, (val)
INCLUDING NEW VALUES;

第一个物化视图:

create materialized view t1_sub_mv1
refresh fast on commit
as
  select id,
         max(version) latest_version,
         count(version) cnt_version,
         count(*) cnt_all
  from   t1
  group by id;

第一个实体化视图上的实体化视图日志:

create materialized view log on t1_sub_mv1
with rowid, sequence (id, latest_version, cnt_version, cnt_all)
including new values;

第二个物化视图:

create materialized view t1_sub_mv2
refresh fast on commit
as
  select id,
         version,
         max(val) max_val_per_id_version,
         count(*) cnt_all
  from   t1
  group by id,
           version;

第一个实体化视图上的实体化视图日志:

create materialized view log on t1_sub_mv2
with rowid, sequence (id, max_val_per_id_version, cnt_all)
including new values;

第三个也是最后一个物化视图:

create materialized view t1_main_mv
refresh fast on commit
as
  select mv1.id,
         mv1.latest_version,
         mv2.max_val_per_id_version val_of_latest_version,
         mv1.rowid mv1_rowid,
         mv2.rowid mv2_rowid
  from   t1_sub_mv1 mv1,
         t1_sub_mv2 mv2
  where  mv1.id = mv2.id
  and    mv1.latest_version = mv2.version;

可以找到支持的测试用例 over at Oracle LiveSQL