【问题标题】:Use a Materialized View to track latest versions of records使用物化视图跟踪最新版本的记录
【发布时间】:2018-02-09 00:54:18
【问题描述】:

我们有一个高度(可能已经结束?)规范化的表,用于跟踪版本化的值。它只是插入,没有更新。

示例数据:

"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: 无法使用实体化视图登录中的筛选列 “模式”。“表”

*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,它只会“工作”。我不知道这是否属于物化视图的“无分析”规则,或者我是否一开始就错误地创建了日志?

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

表架构:

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 

我是否走在正确的轨道上?是否有更好的方法来预先计算最新版本?还是我只需要拨入 Log & View 设置?

【问题讨论】:

  • 您是只查询最新版本的单个 id,还是查询多个 id?另外,你的桌子上有什么索引?您还想在物化视图中存储值吗?
  • 你经常做哪些操作:insert/updateselect?如果select,您多久需要一次实际版本?如果大多数操作是select的实际值,请尝试创建单独的历史表。您的主表将仅包含实际值(并且不需要在 heave 查询中)和更新触发器以将旧版本复制到历史表。此外,Oracle 拥有Flashback 技术。
  • 也许我错了,但SELECT ID, MAX(LAST_VERSION) AS LAST_VERSION FROM TABLE GROUP BY ID 应该足够了。
  • 你需要MAX的解析版吗?我似乎记得你不能在 COMMIT 上刷新 MV,除非它是 FAST Refreshable 并且当视图具有分析功能时你不能快速刷新。
  • IDLAST_VERSION 列添加到您的实体化视图日志中。将COUNT(*) as ROW_COUNT 附加到选择语句。另见docs.oracle.com/cd/B28359_01/server.111/b28313/…

标签: oracle oracle12c materialized-views


【解决方案1】:

很抱歉,我不能马上给你答复。一个原因可能是使用了 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;

【讨论】:

    【解决方案2】:

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

    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 保持在第一个/最后一个的物化视图) - 根据 http://www.sqlsnippets.com/en/topic-12926.html - 就像这样:

    主表的物化视图日志:

    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找到。

    【讨论】:

    • 您的第一个建议应该就足够了,我已经更新了我的代码以匹配您的示例(包括简化的基本查询),但它不会让我另存为 REFRESH FAST(请参阅更新的代码和错误在帖子中)。没有它,提交插入需要几分钟的时间。
    • 好的;我想我已经解决了。我在基表中有其他列,显然也需要将它们添加到日志中,即使它们没有在 MV 中使用。我还使用了 MV 分层技术在结果中添加了额外的数据,谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多