Oracle - 物化视图或表

时间:2015-08-06 14:16:28

标签: oracle

我有一张表(在Oracle 12c中),目前已有2200万条记录,每天还有10,000条记录。我们需要基于此表的计数,例如:

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

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

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

物化视图是否适合此要求,还是应该为它创建常规表?

提前致谢!!!

2 个答案:

答案 0 :(得分: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 *树索引如果只有30个唯一值,则索引应该压缩得很好并且不会占用太多空间。然后可以使用索引 一个快速的完整索引扫描,就像一个瘦的表。此方法至少需要一个值不为null。如果两者都可以为null,那么基于函数 索引在这里很有用。

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

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

答案 1 :(得分:0)

根据您的方法的近似程度,您还可以尝试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;