【问题标题】:Oracle - materialized view or tableOracle - 物化视图或表
【发布时间】:2015-08-07 14:57:30
【问题描述】:

到目前为止,我有一个包含 2200 万条记录的表(在 Oracle 12c 中),并且每天插入 10000 条记录。我们需要根据这张表进行计数,如:

select col1, col2, count(*) cnt from my_table group by col1, col2;

此查询将返回少于 30 行,col1col2 的组合将是唯一的。

我们的应用程序需要经常检查CNT 的值,但CNT 的近似值已经足够了。这意味着我们可以创建一个物化视图并每 10-20 分钟刷新一次。

物化视图是这个需求的好选择,还是我应该为它创建一个常规表?

提前致谢!!!

【问题讨论】:

  • MView 本身使用从视图返回的数据创建一个表。所以我看不出区别
  • @ILLUMINATI7590,是的,MV 只是基于视图的表。但是,通过一个简单的 create 语句,它可以创建表、视图、用于填充和刷新表的计划作业;简而言之,这就像一站式购物。在合适的情况下,MV 非常好用。
  • 也许在col1col2 上创建位图索引(每列一个)。那么查询应该会快很多。

标签: oracle


【解决方案1】:

至少有三种不同的方法可以实现这一点:

  1. 快速刷新实体化视图 快速刷新实体化视图可能是理想的解决方案。插入的 10,000 行会产生少量开销,但无需重新构建任何内容;每次提交后,新总数立即可用,检索新总数将非常快。缺点是快速刷新物化视图很难设置,并且有很多奇怪的陷阱。它们适用于您的示例架构,但可能不适用于更复杂的场景。

    示例架构

    drop table my_table;
    
    create table my_table(
        id number not null,
        col1 number not null,
        col2 number not null,
        constraint my_table_pk primary key (id)
    );
    
    insert into my_table
    select level, mod(level, 30), mod(level+1, 30)
    from dual
    connect by level <= 100000;
    
    begin
        dbms_stats.gather_table_stats(user, 'MY_TABLE');
    end;
    /
    

    创建物化视图日志和物化视图

    create materialized view log on my_table with rowid(col1, col2) including new values;
    
    create materialized view my_table_mv
    refresh fast on commit
    enable query rewrite as
    select col1, col2, count(*) total
    from my_table
    group by col1, col2;
    

    查询重写

    示例查询被静默修改为使用小物化视图而不是大表。

    explain plan for
    select col1, col2, count(*) cnt
    from my_table
    group by col1, col2;
    
    select * from table(dbms_xplan.display);
    
    Plan hash value: 786752524
    
    --------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |             |    30 |   300 |     3   (0)| 00:00:01 |
    |   1 |  MAT_VIEW REWRITE ACCESS FULL| MY_TABLE_MV |    30 |   300 |     3   (0)| 00:00:01 |
    --------------------------------------------------------------------------------------------
    
  2. 压缩的 B*Tree 索引 如果只有 30 个唯一值,则索引应该可以很好地压缩并且不会占用太多空间。那么索引可以用在 快速的全索引扫描,就像一张瘦桌子。此方法要求至少有一个值不为空。如果两者都可以为空,则基于函数 index 在这里可能很有用。

    create index my_table_idx on my_table(col1, col2) compress;
    
  3. 位图索引 当有少量不同的值时,位图索引小而快。但是它们可能会引入灾难性的锁定问题 对于某些类型的 DML。

    create bitmap index my_table_idx on my_table(col1, col2);
    

【讨论】:

  • 如果使用直接路径方法 /*+ APPEND */ 将行插入到表中,那么您可以顺便放弃使用物化视图日志。
  • @DavidAldridge 我将进行编辑以更清楚地说明我正在讨论三种不相关的方法。物化视图日志是物化视图所必需的。这样添加 10,000 条记录不需要重建整个表。
  • 不,我认为答案很清楚。我只是说(主要针对未来的读者)如果对表的唯一更改是通过直接路径插入,则提交时快速刷新不需要 MV 日志——它们不会在 MV 日志中表示,并且 Oracle 使用直接路径插入的提交时快速刷新的不同机制。
  • 我正在绞尽脑汁寻找用于代替 MV 日志的直接路径快速刷新的系统表的名称,但它让我无法理解。
  • 给你——我知道我已经写了一些关于这个的东西。 oraclesponge.wordpress.com/2005/11/23/…
【解决方案2】:

根据您的方法的近似程度,您还可以尝试使用 SAMPLE 子句:

select col1,
       col2,
       count(*) cnt
from   my_table sample(1)
group by col1, col2;

根据值的数据分布,这可能会给出合理的估计。您可以测试需要多高的数字才能给出合理的结果,但除非使用 block 子句,否则很少值得超过 4 或 5:

select col1,
       col2,
       count(*) cnt
from   my_table sample block(10)
group by col1, col2;

【讨论】:

    猜你喜欢
    • 2012-07-17
    • 2023-04-11
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    相关资源
    最近更新 更多