在Oracle 11g中使用虚拟列进行数据建模(下)

日期: 2009-09-23 作者:Jeffrey R. McCormick翻译:孙瑞 来源:TechTarget中国 英文

示例   现在让我们来演示一下虚拟列在模拟数据仓库设计中的具体使用。   1、创建一个标准化PRODUCT表,使用立体的星型模式设计。 create table product    (product_key    number(6)      not null    ,description    varchar2(1000) not null ……

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

示例

  现在让我们来演示一下虚拟列在模拟数据仓库设计中的具体使用。

  1、创建一个标准化PRODUCT表,使用立体的星型模式设计。

create table product
   (product_key    number(6)      not null
   ,description    varchar2(1000) not null
   ,cost           number (7,0)   not null
   ,markup_percent number (3,0)   not null 
  ,total_cost     number (7,0)   as (cost * (1 + (markup_percent / 100))) virtual not null
                                  check (total_cost < 125001)      
   ,states         number         not null
   ,az_flag        varchar2(1)    as (decode(bitand (states,1),1,'Y','N')) virtual not null
   ,ct_flag        varchar2(1)    as (decode(bitand (states,2),2,'Y','N')) virtual not null
   ,ri_flag        varchar2(1)    as (decode(bitand (states,4),4,'Y','N')) virtual not null          
   )
   partition by range (total_cost)
     (
      partition low_cost_partition      values less than (1000)
     ,partition moderate_cost_partition values less than (10000)
     ,partition high_cost_partition     values less than (MAXVALUE)
     );

  请注意加粗的虚拟列新语法。运算属性“total cost”内联为空,它被当做分割列。每个派生的state flag属性都是基于“state”列。

STATE           STATE NUMBER
------------    ------------
ARIZONA                    1          
CONNECTICUT                2        
RHODE ISLAND               4 

  2、显示的虚拟列表达式实际以元数据的形式存储在数据字典中。

select column_name, virtual_column, data_default 
  from user_tab_cols 
  where table_name = 'PRODUCT'
  order by column_id;
COLUMN_NAME                    VIR DATA_DEFAULT
------------------------------ --- ------------------------------------
PRODUCT_KEY                    NO
DESCRIPTION                    NO
COST                           NO
MARKUP_PERCENT                 NO
TOTAL_COST                     YES "COST"*(1+"MARKUP_PERCENT"/100)
STATES                         NO
AZ_FLAG                        YES DECODE(BITAND("STATES",1),1,'Y','N')
CT_FLAG                        YES DECODE(BITAND("STATES",2),2,'Y','N')
RI_FLAG                        YES DECODE(BITAND("STATES",4),4,'Y','N')

  3、加载PRODUCT表

insert /*+ APPEND */ into product
  (PRODUCT_KEY,DESCRIPTION,COST,MARKUP_PERCENT,STATES)  
  select rownum
        ,rpad(to_char(rownum),1000)
        ,case floor(dbms_random.value(1,6))  
           when  1 then  10
           when  2 then  100
           when  3 then  1000
           when  4 then  10000
           when  5 then  100000
         end  
        ,case floor(dbms_random.value(1,4))  
           when  1 then  5
           when  2 then  10
           when  3 then  25
         end          
        ,case floor(dbms_random.value(1,3))  
           when  1 then  1
           when  2 then  3
         end  
    from  dba_objects 
    where rownum < 50001;
commit;

  4、 在虚拟“state flag ”列中创建本地分割索引。

create bitmap index product_az_ix on product (az_flag) local;
create bitmap index product_ct_ix on product (ct_flag) local;
create bitmap index product_ri_ix on product (ri_flag) local;

select a.index_name, a.index_Type, b.column_Expression
  from user_indexes         a
      ,user_ind_expressions b
  where a.index_name    = b.index_name 
    and a.index_name like 'PRODUCT_%_IX';
INDEX_NAME    INDEX_TYPE            COLUMN_EXPRESSION
------------- --------------------- ------------------------------------
PRODUCT_AZ_IX FUNCTION-BASED BITMAP DECODE(BITAND("STATES",1),1,'Y','N')
PRODUCT_CT_IX FUNCTION-BASED BITMAP DECODE(BITAND("STATES",2),2,'Y','N')
PRODUCT_RI_IX FUNCTION-BASED BITMAP DECODE(BITAND("STATES",4),4,'Y','N')

  5、收集统计数据

execute dbms_stats.gather_table_stats(user,'PRODUCT' ,cascade=>true, estimate_percent=> 100, granularity=> 'PARTITION');
select blocks, num_rows, avg_row_len from user_tables where table_name = 'PRODUCT';
    BLOCKS   NUM_ROWS AVG_ROW_LEN
---------- ---------- -----------
      7284      50000        1024

  6、验证ARIZONA和RHODE ISLAND的偏态分布。

select states,count(*) from product group by states order by states;
    STATES   COUNT(*)
---------- ----------
         1      24910
         3      25090
select ' ARIZONA'     ,sum(decode(az_flag,'Y',1,0)) "AZ Yes"
                      ,sum(decode(az_flag,'N',1,0)) "AZ No"
      ,' RHODE ISLAND',sum(decode(ri_flag,'Y',1,0)) "RI Yes"
                      ,sum(decode(ri_flag,'N',1,0)) "RI No"
  from product;
 'ARIZONA     AZ Yes      AZ No 'RHODEISLAND'     RI Yes      RI No
 -------- ---------- ---------- ------------- ---------- ----------
  ARIZONA      50000          0  RHODE ISLAND          0      50000

  7、比较ARIZONA和RHODE ISLAND的优化查询计划。

select /*+ gather_plan_statistics */ product_key from product where az_flag = 'Y';
PRODUCT_KEY
-----------
          1
.
.
.
      49999
50000 rows selected.
select * from table(dbms_xplan.display_cursor(null,null,'allstats cost last'));
---------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name    | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers | Reads  |
---------------------------------------------------------------------------------------------------------------
|   1 |  PARTITION RANGE ALL|         |      1 |  50000 |  1979   (1)|  50000 |00:00:00.61 |   10011 |   7147 |
|*  2 |   TABLE ACCESS FULL | PRODUCT |      3 |  50000 |  1979   (1)|  50000 |00:00:00.46 |   10011 |   7147 |
---------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(DECODE(BITAND("STATES",1),1,'Y','N')='Y')

select /*+ gather_plan_statistics */ product_key from product where ri_flag = 'Y';
no rows selected
select * from table(dbms_xplan.display_cursor(null,null,'allstats cost last'));

---------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name          | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------------------
|   1 |  PARTITION RANGE ALL               |               |      1 |      1 |     4   (0)|      0 |00:00:00.01 |       5 |
|   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| PRODUCT       |      3 |      1 |     4   (0)|      0 |00:00:00.01 |       5 |
|   3 |    BITMAP CONVERSION TO ROWIDS     |               |      3 |        |            |      0 |00:00:00.01 |       5 |
|*  4 |     BITMAP INDEX SINGLE VALUE      | PRODUCT_RI_IX |      3 |        |            |      0 |00:00:00.01 |       5 |
---------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("RI_FLAG"='Y')

  在这里,列函数的偏差结果可以被优化器捕获。这造成优化器对待每个查询成本的方式会有所不同,从而制定不同的查询计划。注意,估计行数要和实际处理行数匹配。

  在这里,我们看到优化器针对“total cost”虚拟列进行了分区修剪。

select count(*) from product where total_cost > 10000;
  COUNT(*)
----------
     19885
select * from table(dbms_xplan.display_cursor);
---------------------------------------------------------------------------------------------------
| Id  | Operation               | Name    | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |       |       |   788 (100)|          |       |       |
|   1 |  SORT AGGREGATE         |         |     1 |    13 |            |          |       |       |
|   2 |   PARTITION RANGE SINGLE|         | 19885 |   252K|   788   (1)| 00:00:10 |     3 |     3 |
|*  3 |    TABLE ACCESS FULL    | PRODUCT | 19885 |   252K|   788   (1)| 00:00:10 |     3 |     3 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("COST"*(1+"MARKUP_PERCENT"/100)>10000)

  虚拟列是Oracle 11g提供的一个非常有用的功能。这一功能为数据建模人员提供了显示逻辑属性的优化方案。充分理解数据库的特性可以版主你更加简单更加快速地进行数据仓库设计。

翻译

孙瑞
孙瑞

相关推荐

  • 数据库设计需做好前期工作 Agile方法不适合

    有很多企业认为数据建模以及设计良好的数据库是浪费时间的工作,对此专家的回答很直接:决不能忽视数据库设计过程。

  • SAP HANA数据建模秘籍

    SAP HANA是一个全新的数据库平台,它提供了全新的数据建模方式,使得传统关系型数据库管理系统(RDBMS)得到了进一步的扩展。

  • NoSQL数据建模技术

    NoSQL 数据库经常被用作很多非功能性的地方,如,扩展性,性能和一致性的地方。这些NoSQL的特性在理论和实践中都正在被大众广泛地研究着。

  • TDWI解决方案峰会分享主数据管理最佳实践

    在近期召开的TDWI(数据仓库协会)解决方案峰会上,几位从事主数据管理(MDM)和数据治理的专家以演讲方式分享了他们的经验和MDM最佳实践。