存档

‘Oracle’ 分类的存档

测验Oracle 的小游戏

2009年4月2日 没有评论

在eddie award 站点上看到的,   http://www.db-quest.com/

http://awads.net/wp/2009/03/25/play-this-game-to-find-out-if-you-are-the-smartest-database-professional-in-the-world/

 

非常多的oracle ace 组织的一个游戏,测试你是不是最聪明的DBA , 目前我答的题目已经涉及到操作系统,oracle , 普通的sql 知识, pl/sql , 系统架构,我挂的很早,估计后面应该还有更专业的,比如备份,rac , dw 等等,第一次玩,第一关就挂了,完全没搞清楚怎么回事,时间限制太强了,一个题读一遍没懂,第二篇读完就没时间了,一定要非常熟(或者靠运气), 第二次打到第四关,

 

db-quest2

你要是能进前10 就可以提一个问题,最高的那个1M , 佩服呀,关键是时间限制非常强,完全不给时间你想,神经要蹦的很紧. 目前56k 就可以进前10 ,应该还算不BT ,

最后那个小人做一个手枪的动作(上图左上方),让我想起了boston legel s4e17 最高院之战,Jerry 说I lost my cherry , 然后Allen 走出办公室的时候回了一个手枪的动作.  无限怀念呀.

 

各位推荐给Oracle DBA 的好友吧,如果有高分数,拿来炫耀一下,他上面有challenge a friend 选项嘛.

分类: Oracle 标签:

Oracle OLAP 使用mv 刷新Cube

2009年3月7日 没有评论

上一篇文章中介绍了oracle 11g 中的部分olap 新功能,这篇介绍如何使用mv 刷新cube 的数据.

默认的如果你创建了一个cube ,cube 里面的数据只有在你手工执行

dbms_cube.build(‘<cube_name>’) 才会刷新.

 

比如你在前面已经建立好了global 的price_cube , 并且执行了第一次dbms_cube.build(‘price_cube’) 你才能查询到数据. 比如执行以下sql:

select * from table(cube_table(‘price_cube’))

where product=’ITEM_ENVY STD’  and time=’MONTH_1998.01′;

此时输出如下 (注意大小写,下划线和空格):

unit_cost    unit_price    time                        product

3346.85     3480.92       MONTH_1998.01     ITEM_ENVY STD

现在我们手工更新price_fact 表的这条数据(price_cube 的实际数据来源),

update price_fact set unit_price=9999

where month_id=1998.01 and item_id=’ENVY STD’;

1 rows updated

现在重新查看price_cube 的数据,你会发现跟刚才的一样, unit_price 还是等于3480.92 , 而不是随着price_fact 表的数据更新到9999.

 

启用Cube MV  刷新数据的前提条件

如果你希望你的cube 随着实体表的更新而刷新的话(不一定要是同步), 你就需要把cube 设置成按mv 方式来组织. 不过首先你需要满足以下几个条件:

  1. 所有的dimension 必须至少有一个level 和 hierarchy
  2. 所有的dimension 必须使用同一种聚合操作, sum,min,max 等等.
  3. 一个cube 的所有属性必须正确的映射到实体表. 一个cube 可以有calculated measures , 但是不能映射到mv , 如果一个cube 的脚本中有高级分析函数也不能映射.
  4. dimension 和fact table 之间必须要有约束.至少是外键约束. 如果你没有定义,你可以在启用mv 的时候用Relational Schema Advisor 帮你映射.
  5. 所有的表上的约束必须同一类型.
  6. cube 被压缩了.
  7. 为了更好的使用query rewrite , 你应该创建relational dimension 对象
    关于第二点,otn 上给的global_schema 的price_cube 的聚合操作就不是同一的sum 操作,所以你启用mv 刷新的时候会报错,注意根据错误信息调整.
    关于第三点, calculated measure 支持的分析函数:
    awm_calculated_measure_advanced_analysis
    除了在第一个文件夹 简单算术 文件夹下的六个(+,-,×,/,%) , 其他都算高级分析函数.
    关于第四点,fact table 和dimension table 之间至少要有外键约束, 这应该是建模标准之一,如果不是多维数据集 比如11g 之前的类型,你可以方便的在外键之间建立组合索引. 对于11g 的cube 类型来说,必须需要至少外键约束.
    关于第六点,默认的用awm 创建的cube 里面的是没有指定压缩类型和压缩比率的,只有在第一次刷新之后,再启用mv 刷新的时候才能选择压缩选项. awm 里面有提示,注意参考提示信息.
    关于第七点最重要, 所谓relational dimension 就是我们通过create dimension 创建的对象. 而我们之前说的dimension 一般都是指cube dimension , 它指的是在analysis workspace 里面的dimension 对象.

relational dimension 你可以通过查看dba_dimensions 视图查看. 主要用来控制mv query rewrite 的.

cube dimension 可以通过查看dba_cube_dimensions 视图查看. 另外两个跟aw 相关的视图是dba_cubes 和dba_aws ,

11g 有一些新的跟aw 相关的试图,你可以查看

SELECT * FROM dba_objects WHERE object_name LIKE ‘%AW%’;

其中包括了dimension 和cube 的元数据,dimension 和cube 的统计图信息(analyze 之后收集的),  dimension 和cube mv 的元数据, cube 的分区建议和储存建议. 具体查看oracle 11g 的文档.

默认的你创建cube 的时候,它会创建对应的relational dimension (awm 里面是这样, 手工从pl/sql 里面创建没试过), 你可以删除relational dimension , cube 里面的dimension 是不会跟着删除的.

 

relational dimension的一些操作

查看dimension 的pl/sql

exec dbms_dimension.describe_dimension('global.product_dimension');

输出:


DIMENSION GLOBAL.PRODUCT_DIMENSION  LEVEL FAMILY IS GLOBAL.PRODUCT_DIM.FAMILY_ID  LEVEL ITEM IS GLOBAL.PRODUCT_DIM.ITEM_ID
LEVEL TOTAL IS GLOBAL.PRODUCT_DIM.TOTAL_ID
LEVEL class IS GLOBAL.PRODUCT_DIM.CLASS_ID
HIERARCHY primary ( ITEM CHILD OF
FAMILY CHILD OF
class CHILD OF
TOTAL
)
ATTRIBUTE FAMILY LEVEL FAMILY DETERMINES GLOBAL.PRODUCT_DIM.FAMILY_DSC
ATTRIBUTE ITEM LEVEL ITEM DETERMINES GLOBAL.PRODUCT_DIM.ITEM_DSC
ATTRIBUTE TOTAL LEVEL TOTAL DETERMINES GLOBAL.PRODUCT_DIM.TOTAL_DSC
ATTRIBUTE class LEVEL class DETERMINES GLOBAL.PRODUCT_DIM.CLASS_DSC

 

启用cube mv 刷新

实际启用cube mv 刷新是很简单的, 主要是前提条件都满足了, 在awm 的cube 里面Materialized Views 选项卡里面点击 Enable Materalized View 选项和 Enable Query Rewrite 选项.

image

刷新模式有Complete , Fast ,Force . 其他可选方法还有PCT (Partition Change Tracking) 和Fast Solve;

1. Complete – 全部删除再全部装载

2. Fast – 使用mv log 记录变化的记录,并且只更新这些记录和对应的聚合记录

3. Force-  默认使用fast, 如果fast 不可用,才使用complete

4. Partition Change Tracking:  只刷新部分分区的数据,这在awm 里面没有

5. Fast Solve:  加载所有的原始数据,但是只计算新数据的聚合值,awm 里面没有

 

mv 不会计算calculated measures , 并且随着mv 的体积增大,创建和刷新的速度会变慢(不是呈线性下降),如果你mv 过大,你应该考虑分割成几个sub cube , 或者去掉一些不用的属性.

你选择使用mv 来刷新数据之后,oracle 会为每一个dimension 的每个hierarchy 都创建一个mv , 并且mv 的名字都是以CB$ 开头, 你是不能控制这些mv 的,只能控制cube . 以下的sql 可以得到所有的cube 对应的mv

 

启用Query Rewrite

要使用query rewrite 必须满足以下条件:

要有create mv 权限和其他相关对象的权限,

  1. 在init.ora 文件中设置QUERY_REWRITE_ENABLED= TRUE 或FORCE , 在session 里面也可以.
  2. 注意awm 里面的检查信息.
  3. 注意查看Relational Schema Advisor ,注意这很重要,Relational Schema Advisor 在mv 选项卡的最下面,上图中最下面那个灰色的按钮. 里面会列出你的schema 不符合query rewrite 的条件. 它会给出sql 让你执行,注意查看这些sql 以避免query rewrite 失败.

你也可能会想要改变约束类型, 从enforced , trusted , norely 到‘RELY’ 因为oracle执行计划消耗会更小

alter table "price_fact" add constraint "xxx_constraint" PRIMARY KEY (ITEM_ID, MONTH_ID, UNIT_PRICE, UNIT_COST) RELY enable validate ;

 

刷新MV

刷新时间点上有三种方式:

on demand , 等待手工刷新

start next ,  定时到将来刷新

on commit ,  每次源表有提交都刷新.

 

推荐的维护mv 刷新还是使用awm , 如果是定时的话就使用下面一些pl/sql.

exec dbms_cube.build(‘PRICE_CUBE’);   — 这是全刷新

可以一句话包含多个cube 或dimension , exec dbms_cube.build(‘PRICE_CUBE, xxx_CUBE , xxx_dimension’);

刷新mv:

exec dbms_mview.refresh(‘CB$PRODUCT_PRIMARY’,'C’);

C 当然是代表complete , 这会刷新所有跟这个dimension 的这个hierarchy 有关的mv

或者exec dbms_mview.refresh(‘CB$PRICE_CUBE’,'F’) 这会以force 方式刷新这个cube 的它对应的mv.

你可以说使用以下sql 查看mv 的状态:

select owner||’.'||mview_name cube_mv, rewrite_enabled, staleness

         from all_mviews

         where container_name like ‘CB$%’;

Staleness 这一栏下有fresh 和stale 两种状态,fresh 表示所有数据都已经最新了, stale 表示有新的数据没有刷新但是mv 仍然可用.

 

MV 的一些注意事项

如果query rewrite 没有使用mv , 则检查:

query_rewrite_enabled =FORCE

query_rewrite_integrity=stale_tolerated

使用dbms_mview.explain_rewrite 查看为什么query rewrite 没有成功.

 

参考资料:

http://www.oracle.com/technology/products/bi/olap/collateral/OLAP_11g_MV_query_rewrite.html?_template=/ocom/print

介绍oracle 11g mv 的

 

http://www.oracle.com/technology/obe/obe10gdb/bidw/mvplans/mvplans.htm

介绍oracle 10g mv 的.

分类: OLAP, Oracle 标签: , , ,

Oracle 11g OLAP 新功能简介

2009年3月5日 1 条评论

oracle 11g 在数据仓库方面也有不少新功能,尤其是新的多维数据集组织的cube (也就是常说的MOLAP).

在开始本文之前,建议先查看otn 上关于介绍oracle 11g 新功能的data warehouse 部分,由oracle ace 总监Arup Nanda 写的, 目前otn 的中文站点已经有翻译版的, 地址如下:

http://www.oracle.com/technology/global/cn/pub/articles/oracle-database-11g-top-features/11g-dw-olap.html?_template=/ocom/print

这篇文章主要介绍上面这篇文章中的一些实验和没有覆盖到的地方. (记住一定先看上面这篇文章)

 

导入数据

首先从http://www.oracle.com/technology/products/bi/olap/doc_sample_schemas/global_11g_schema.zip

下载它的示例数据, 之后使用一个具有DBA 权限的用户建立global 用户,用户名一定要是global (除非你修改里面的一些脚本), 执行

SQL&gt; @global_11g_install

它会要求你输入system 的密码和你希望global 用户的密码

之后就会导入global schema . 一共8个表,默认应该是成功并且没有警告的.

不要执行第二个脚本 global_11g_create_cubes.sql, 虽然它global_11g_readme.html 说明里说要执行第二个脚本,但这个脚本有问题,会失败. 执行了也没关系.

使用AWM

伴随oracle 11g 发布的还有一个AWM (Analysis Workspace Manager) 工具,版本为11.1.0.7 ,  这是个JAVA 工具,需要JDK 5.0 以上, 你可以到下面地址下载:

http://www.oracle.com/technology/global/cn/products/bi/olap/index.html

oracle 11g 引入了 分析工作区 (aw) 来管理跟OLAP 有关的对象, 而awm 就是一个图形化的用来管理aw 的工具.

解压awm 之后, 在命令行下执行

java –jar awm11.1.0.7.0B.jar

awm 启动后,点击 File –> Connect Database , 选Global 作为你要连接的数据库,输入刚才输入的global 用户名和密码. 之后打开分析工作区 , 你应该看到global 工作分析区下面有dimensions , cubes 文件夹,你点开后里面应该是空的(otn 的示例上有是因为执行了上面第二个脚本,但是它给出的下载的文件里这个脚本有问题而没有执行,所以应该是空的).

现在可以导入dimension 和cube 的定义,右键点击Dimension 文件夹,选择 从模板创建 , 然后倒入CHANNEL , CUSTOMER , PRODUCT , TIME dimension , 文件就在global_schema 文件夹下的templates 下, 对cube 也执行一样的操作导入PRICE_CUBE 和 UNIT_CUBE .

 

填充Cube 数据

完成上面操作之后,你应该有了4个dimension 和2个cube , 但是里面都没有数据,你可以使用两种方法从table 里面导入数据,

1. 用pl/sql  , 在sqlplus 里面使用 exec dbms_cube.build(‘PRICE_CUBE’) ;

2, 还是使用awm , 在awm 的cube 文件夹下的PRICE_CUBE 上点右键,选择 维护立方体 .

image

    awm 会让你选择维护的cube 和dimension , 点击Next 之后,再选择 立即运行 , 如果你想看运行的到底是什么,你可以选择保存文件.

image

之后你可以在Build log 对话框里面查看Output 列,

<CommandOutput>
<CubeLoad
Name="MAP1"
SQL="SELECT /*+  bypass_recursive_check  cursor_sharing_exact  no_expand */
  T16_MONTH_ID ALIAS_114,
  T13_ITEM_ID ALIAS_115,
  SUM(T19_UNIT_PRICE)  ALIAS_116,
  SUM(T19_UNIT_COST)  ALIAS_117
FROM
  (
  SELECT
    T1.ITEM_ID T19_ITEM_ID,
    T1.MONTH_ID T19_MONTH_ID,
    T1.UNIT_PRICE T19_UNIT_PRICE,
    T1.UNIT_COST T19_UNIT_COST
  FROM
    GLOBAL.PRICE_FACT T1   )
  T19,
  (
  SELECT
    T1.MONTH_ID T16_MONTH_ID
  FROM
    GLOBAL.TIME_DIM T1   )
  T16,
  (
  SELECT
    T1.ITEM_ID T13_ITEM_ID
  FROM
    GLOBAL.PRODUCT_DIM T1   )
  T13
WHERE
  ((T16_MONTH_ID = T19_MONTH_ID)
    AND (T13_ITEM_ID = T19_ITEM_ID)
    AND (T16_MONTH_ID = T19_MONTH_ID)
    AND (T13_ITEM_ID = T19_ITEM_ID) )
GROUP BY
  (T13_ITEM_ID, T16_MONTH_ID)
ORDER BY
  T13_ITEM_ID ASC NULLS LAST ,
  T16_MONTH_ID ASC NULLS LAST "
LOADED="2523"
REJECTED="0"
</CommandOutput>

完成之后你就可以看到cube 里面的数据了.

 

查看数据

Oracle 11 g引入一个新的函数cube_table 让我们使用sql 的语法就可以查看到MOLAP 的数据,语法如下

cube 语法: select * from table(cube_table(‘<schema>.<cube_name>’))

示例 PRICE_CUBE : select * from table(cube_table(‘GLOBAL.PRICE_CUBE’))  (如果你是global 登录的,可以不加前面的global.)

dimension 语法: select * from table(cube_table(‘<schema>.<dimension>;<hierarchy>’))

其中hierarchy 部分是可选的, 比如对于global 用户的product dimension:

select * from table(cube_table(‘global.product’));

如果dimension 只有一个hierarchy ,oracle 当然会选择这个,如果dimension 有两个或两个以上的hierarchy , oracle 使用的就是你指定的默认的那个, time dimension 就有CALENDAR 和FISCAL 两个hierarchy , calendar 就是默认的那个,所以你查询time dimension 时没有指定hierarchy , 实际就是查询的calendar hierarchy.

对于每一个cube 和dimension ,oracle 都会创建相应的view , 所以你查询cube 和 dimension 的时候,也是查询的对应的view.

比如global schema 就会默认的创建下面这些view (在你建立cube 的时候) : product_view , product_parmary_view , time_view , time_calendar_view, time_fiscal_view , price_cube_view.

每个dimension 会默认创建 <dimension_name>_view 和 <dimension_name>_<hierarchy_name>_view , cube 则会对应 <cube_name>_cube_view

所以你执行select * from table(cube_table(xxx)); 的时候实际上就是查询的view

比如其中price_cube_view 的定义就是如下:

1
<p>&#160; CREATE OR REPLACE FORCE VIEW &quot;GLOBAL&quot;.&quot;PRICE_CUBE_VIEW&quot; (&quot;UNIT_COST&quot;, &quot;UNIT_PRICE&quot;, &quot;TIME&quot;, &quot;PRODUCT&quot;) AS   <br />&#160; SELECT   <br />&#160;&#160;&#160; &quot;UNIT_COST&quot;,  <br />&#160;&#160;&#160; &quot;UNIT_PRICE&quot;,&#160;&#160;&#160;&#160; </p><p>    &quot;TIME&quot;,&#160;&#160;&#160;&#160; </p><p>    &quot;PRODUCT&quot;&#160;&#160; FROM TABLE(CUBE_TABLE('GLOBAL.PRICE_CUBE') ) ;</p>

 

cube 的过滤,排序和聚合

更复杂一点的sql:

SELECT * FROM TABLE(CUBE_TABLE(

   ‘global.price_cube HIERARCHY product primary HIERARCHY time calendar’))

   where TIME=’TOTAL_TOTAL’

   ORDER BY PRODUCT  
   ;

 

SELECT SUM(UNIT_COST),SUM(UNIT_PRICE),PRODUCT  FROM TABLE(CUBE_TABLE(

   ‘global.price_cube HIERARCHY product primary HIERARCHY time calendar’))

   where TIME=’TOTAL_TOTAL’  
   GROUP BY PRODUCT

   ORDER BY PRODUCT  
   ;

 

跟普通的sql 基本一样,除了cube_table 里面的写法需要注意一点外, 如果你喜欢通过GUI 界面来看的话,awm 里面右键点击cube 选查看数据.  还可以点击维度展开 , 下面还有图表.

awm_view_cube_data

在查讯构建器里面(上图中 文件 菜单那个下面那个按钮)还可以选择构建复杂的.

awm_query_build

这个界面倒是跟owb 里面的完全一样,估计用的同一代码

owb_sshot-6

最原始的模型应该是从essbase 借鉴过来的,界面布局和操作方式都跟essbase 非常像.

 

 

如何管理cube

并没有直接的pl/sql 可以来删除或者修改cube , 目前dbms_cube 包里面就三个函数 build() , import_xml , validate_xml().  build() 是用来填充数据的 . 如果你对cube 的定义不满意的话,要修改或者删除的话,一般都是通过awm ,  otn 上面给出的那个global_schema 文件里倒是有一个删除的例子,手工拼接xml , 然后dbms_cube.import(xml).

  set serverout on

  declare      xmlCLOB   clob;      v_i       number;      type t_dims is table of all_cube_dimensions%rowtype;      type t_cubes is table of all_cubes%rowtype;      v_dims    t_dims;      v_cubes   t_cubes;      v_cmd     varchar2(400);    

  begin      -- Check if the AW exists
    dbms_output.put_line('... checking for GLOBAL AW in GLOBAL schema');     SELECT COUNT(*)      INTO v_i     FROM all_aws     WHERE owner = 'GLOBAL'      AND aw_name = 'GLOBAL';


    -- Delete the AW if it exists     if v_i > 0 then       dbms_output.put_line('... deleting GLOBAL AW in GLOBAL schema');        dbms_lob.createtemporary(xmlCLOB,TRUE);        dbms_lob.open(xmlCLOB, DBMS_LOB.LOB_READWRITE);        dbms_lob.writeappend(xmlCLOB, 9, '<Metadata');        dbms_lob.writeappend(xmlCLOB, 16, '  Version="1.1">');        dbms_lob.writeappend(xmlCLOB, 5, '  <AW');        dbms_lob.writeappend(xmlCLOB, 19, '    Action="REMOVE"');        dbms_lob.writeappend(xmlCLOB, 18, '    Owner="GLOBAL"');        dbms_lob.writeappend(xmlCLOB, 19, '    Name="GLOBAL"/>');        -- Loop over each of the Dimensions in the AW and delete them        select *  bulk collect  into v_dims   from all_cube_dimensions        where owner = 'GLOBAL'  and aw_name = 'GLOBAL';
        for i in 1 .. v_dims.count loop          v_cmd := '<' || initcap(v_dims(i).dimension_type) || 'Dimension';          dbms_lob.writeappend(xmlCLOB, length(v_cmd), v_cmd);        dbms_lob.writeappend(xmlCLOB, 19, '    Action="REMOVE"');        dbms_lob.writeappend(xmlCLOB, 18, '    Owner="GLOBAL"');         v_cmd := '    Name="' || v_dims(i).dimension_name || '"/>';         dbms_lob.writeappend(xmlCLOB, length(v_cmd), v_cmd);              end loop; 

     -- Loop over each of the cubes and delete them
        select * bulk collect into v_cubes         from all_cubes        where owner = 'GLOBAL'          and aw_name = 'GLOBAL';        for i in 1 .. v_cubes.count loop          dbms_lob.writeappend(xmlCLOB, 7, '  <Cube');        dbms_lob.writeappend(xmlCLOB, 19, '    Action="REMOVE"');          dbms_lob.writeappend(xmlCLOB, 18, '    Owner="GLOBAL"');         v_cmd := '    Name="' || v_cubes(i).cube_name || '"/>';                      dbms_lob.writeappend(xmlCLOB, length(v_cmd), v_cmd);       end loop;            -- Finish off the removal tags
        dbms_lob.writeappend(xmlCLOB, 11, '</Metadata>');            dbms_lob.close(xmlCLOB);            dbms_output.put_line(xmlCLOB);       --  dbms_cube.import_xml(xmlCLOB);       commit;     else       dbms_output.put_line('... GLOBAL AW in GLOBAL schema not found');     end if;     exception       when others then         dbms_output.put_line(' ');         dbms_output.put_line('# ERROR:  Installation failed.');         dbms_output.put_line('# Please ensure that the analytic workspace GLOBAL is not currently open.');         raise_application_error(-20000, 'Can not delete analytic workspace that is currently in use.');
end;
/

我把dbms_cube.import_xml() 那一行注释掉了,输出类似如下:


<Metadata  Version="1.1">  <AW    Action="REMOVE"    Owner="GLOBAL"  Name="GLOBAL"/><StandardDimension    Action="REMOVE"    Owner="GLOBAL"  Name="CHANNEL"/><StandardDimension    Action="REMOVE"    Owner="GLOBAL"  Name="CUSTOMER"/><TimeDimension    Action="REMOVE"    Owner="GLOBAL"  Name="TIME"/><StandardDimension    Action="REMOVE"    Owner="GLOBAL"  Name="PRODUCT"/>  <Cube    Action="REMOVE"    Owner="GLOBAL"  Name="PRICE_CUBE"/></Metadata>

你可以看到它执行删除操作就是通过Action = "REMOVE" .

 

最后

关于cube 的数据储存和刷新 下一篇介绍,另外还有关于oracle 11g 的OLAP 新特性 更频繁地执行查询重写  ,

分区中的陈旧程度检查  otn上都有介绍, 大家可以去看看

 

参考资料

http://www.oracle.com/technology/global/cn/pub/articles/oracle-database-11g-top-features/11g-dw-olap.html?_template=/ocom/print

otn 上介绍oracle 11g olap 新功能的文章.

 

http://www.oracle.com/technology/products/bi/olap/collateral/OLAP_11g_MV_query_rewrite.html?_template=/ocom/print

介绍cube mv 的刷新方式的文章

 

http://www.dba-oracle.com/t_olap_dimensions_cubes.htm

11g 之前的一篇介绍olap 概念的文章, 由oracle ace Mark Rittman 所写, 其中有关于如何在pl/sql 中创建和维护cube 的代码(awm 操作起来还是更简单些)

分类: OLAP, Oracle 标签: , , ,

dynamic sampling 和 multi-column statistics

2009年2月8日 没有评论

oracle 在11g 中引入了新的multi-column statistics 以解决在多个列上过滤数据出现的无法预测潜在的数据分布而产生错误的执行计划的情况, 在11g 之前如果想比较准确的预测多个列上数据过滤的sql 执行计划是否够好可以使用hints /*+ dynamic_sampling(table_name integer)*/ ,

比如一个人的出生月份可以是1-12月任意一个,而他可能的星座也可能是12星座的任意一个,如果问一个人出生于12月又是双鱼的可能性是多少, 数学概率上就应该是1/12*1/12 = 1/144 , 但是双鱼座要么是2月要么是三月,所以实际某个人既出生于某一个月又是某个星座的概率应该是2/12 = 1/6 , 如果让数据库知道两个列以上的这种潜在的关系就可以让数据库选择更好的执行计划.

在otn 上看到文章描写dynamic sampling 和multi-column statistics 的,所以做了以下实验.

  1. create table dynsample (c1 number,c2 number,c3 number,c4 number,c5 number,c6 number);
  2. begin
      for i in 1..5 loop
        for j in 1..10000 loop
          insert into dynsample values(i,i,i,i,i,i);
        end loop;
      end loop;
    end;
    /
  3. exec dbms_stats.gather_table_stats(null,’dynsample’,method_opt=>’for all columns size 1 for columns c1 size 254 for columns c2 size 254′);
    set autotrace traceonly explain
  4. select * from dynsample where c1=1 and c2=1;

    ——————————————————————————-
    | Id   | Operation                  | Name            | Rows  
    ——————————————————————————-
    |   0  | SELECT STATEMENT   |                    |  1991 
    |*  1 |  TABLE ACCESS FULL  | DYNSAMPLE |  1991 
    ——————————————————————————-

    这个时候优化器的预测是对的,c1=1 的情况应该是1/5 , c2=1 的情况也应该是1/5 , 所以当c1=1 and c2=1 的时候应该是50000 * 1/5 * 1/5 = 2000 .

  5. 我们用dynamic_sampling hints 重新跑一遍.

            select /*+ dynamic_sampling(dynsample 4) */ * from dynsample where c1=1 and c2=1;

    ———————————————–
    | Id   | Operation                  | Name           | Rows  |
    ———————————————–
    |   0  | SELECT STATEMENT  |                    | 10000 |
    |*  1 |  TABLE ACCESS FULL | DYNSAMPLE  | 10000 |
    ———————————————–

    使用dynamic_sampling 之后出来的预测是代表真实的情况,

  6. exec dbms_stats.gather_table_stats(‘alex’,'dynsample’,method_opt=>’for all columns size 1 for columns(c1,c2) size 254′);

    使用11g 的新的multi-column statistics 来收集关于c1 和c2 的组合统计信息

  7. select * from dynsample where c1=1 and c2=1;

    ———————————————–
    | Id   | Operation                  | Name            | Rows  |
    ———————————————–
    |   0  | SELECT STATEMENT   |                    | 10051 |
    |*  1 |  TABLE ACCESS FULL  | DYNSAMPLE | 10051 |
    ———————————————–

            这时候的统计信息也是正确的.

  8. 换一个没有统计值的sql

            select * from dynsample where c1=1 and c3=1;

    ———————————————–
    | Id   | Operation                  | Name           | Rows  |
    ———————————————–
    |   0  | SELECT STATEMENT  |                    |  2000 |
    |*  1 |  TABLE ACCESS FULL | DYNSAMPLE |  2000 |
    ———————————————–

     

  9. 重新使用dynamic sampling 看看

select /*+dynamic_sampling(dynsample 4) from dynsample where c1=1 and c3=1;

———————————————–
| Id   | Operation                  | Name            | Rows  |
———————————————–
|   0  | SELECT STATEMENT  |                     | 10000 |
|*  1 |  TABLE ACCESS FULL | DYNSAMPLE  | 10000 |
———————————————–

 

 

11g 的multi-column statistics 的语法基本跟之前收集统计值的语法一样. 如果sql 有使用多个列的联合过滤的时候,11g的优化器就会使用multi-column statistics.

注意dynamic sampling 要使用级别4 以上的才能收集到multi-column 的统计信息.

dynamic sampling hints 在9i r2之后都可以使用. 使用的时候会耗费更多的解析时间, 一般来说会建议在统计信息不是很准确,解析时间不重要, 正确的执行计划至关重要的情况下,像是数据仓库里面的报表 或是OLTP 中不是运行非常频繁的sql.

顺便贴出dynamic sampling 的11个级别分别代表什么.

  • Level 0: Do not use dynamic sampling.
  • Level 1: Sample all tables that have not been analyzed if the following criteria are met: (1) there is at least 1 unanalyzed table in the query; (2) this unanalyzed table is joined to another table or appears in a subquery or non-mergeable view; (3) this unanalyzed table has no indexes; (4) this unanalyzed table has more blocks than the number of blocks that would be used for dynamic sampling of this table. The number of blocks sampled is the default number of dynamic sampling blocks (32).
  • Level 2: Apply dynamic sampling to all unanalyzed tables. The number of blocks sampled is two times the default number of dynamic sampling blocks.
  • Level 3: Apply dynamic sampling to all tables that meet Level 2 criteria, plus all tables for which standard selectivity estimation used a guess for some predicate that is a potential dynamic sampling predicate. The number of blocks sampled is the default number of dynamic sampling blocks. For unanalyzed tables, the number of blocks sampled is two times the default number of dynamic sampling blocks.
  • Level 4: Apply dynamic sampling to all tables that meet Level 3 criteria, plus all tables that have single-table predicates that reference 2 or more columns. The number of blocks sampled is the default number of dynamic sampling blocks. For unanalyzed tables, the number of blocks sampled is two times the default number of dynamic sampling blocks.
  • Levels 5, 6, 7, 8, and 9: Apply dynamic sampling to all tables that meet the previous level criteria using 2, 4, 8, 32, or 128 times the default number of dynamic sampling blocks respectively.
  • Level 10: Apply dynamic sampling to all tables that meet the Level 9 criteria using all blocks in the table.

10 r1 有个sql profile 功能,它跟dynamic sampling 的区别就是把sql 执行计划里面统计过的数据持久化, dynamic sampling 是不保存统计信息的.

 

参考资料

http://www.oracle.com/technology/oramag/oracle/09-jan/o19asktom.html

tom 写的dynamic sampling 的文章

 

http://www.oracle.com/technology/obe/demos/11gr1/11gr1_beta1_multi_col_stats/11gr1_beta1_multi_col_stats_viewlet_swf.html

演示11g 的multi-column statistics 的新特性

Oracle 所有的hints

2009年1月3日 没有评论

oracle 10g 有64个hints , 11g 增加到71 个, 下表中红色的代表已经过时的, 粗体的是11g 新增, CBO 中RULE hints 当然也不算了.

Optimization Goals and Approaches (2)

Access Path Hints (17)

Other (20)

Join Operation (7)

ALL_ROWS

FIRST_ROWS

RULE

CLUSTER

FULL

HASH

INDEX

NO_INDEX

INDEX_ASC

INDEX_DESC

INDEX_COMBINE

INDEX_JOIN

INDEX_FFS

INDEX_SS

INDEX_SS_ASC

INDEX_SS_DESC

NATIVE_FULL_OUTER_JOIN

NO_NATIVE_FULL_OUTER_JOIN

NO_INDEX_FFS

NO_INDEX_SS

APPEND

NOAPPEND

CACHE

NOCACHE

CURSOR_SHARING_EXACT

DRIVING_SITE

DYNAMIC_SAMPLING

MODEL_MIN_ANALYSIS

MONITOR

NO_MONITOR

OPT_PARAM

PUSH_PRED

NO_PUSH_PRED

PUSH_SUBQ

NO_PUSH_SUBQ

PX_JOIN_FILTER

NO_PX_JOIN_FILTER

QB_NAME

RESULT_CACHE

NO_RESULT_CACHE

USE_HASH

NO_USE_HASH

USE_MERGE

NO_USE_MERGE

USE_NL

USE_NL_WITH_INDEX

NO_USE_NL

Join Order (2)

Query Transformation (13)

XML (2)

Parallel Execution (5)

ORDERED

LEADING

FACT

NO_FACT

MERGE

NO_MERGE

NO_EXPAND

USE_CONCAT

REWRITE

NO_REWRITE

NOREWRITE*

UNNEST

NO_UNNEST

STAR_TRANSFORMATION

NO_STAR_TRANSFORMATION

NO_QUERY_TRANSFORMATION

NO_XMLINDEX_REWRITE

NO_XML_QUERY_REWRITE

PARALLEL

NOPARALLEL*

NO_PARALLEL

PARALLEL_INDEX

NO_PARALLEL_INDEX

NOPARALLEL_INDEX*

PQ_DISTRIBUTE

 

 

参考资料

http://www.dbasupport.com/oracle/ora11g/Optimizer-Hints.shtml

分类: Oracle 标签:

SQL Developer 的几个小技巧

2009年1月3日 没有评论
  1. 录制脚本并回放 , 比较适合用于重复的工作.

    From the JDeveloper 10g (10.1.3) Documentation:
    To define accelerators for recording and playing back:
    1. From the main menu, choose Tools then choose Preferences.
    2. In the Preferences dialog, select the Accelerators node.
    3. On the Accelerators page, in the Category list select Code Editor.
    4. In the Actions list, select Macro Toggle Recording.
    5. Put the focus in the New Accelerator field, and enter an accelerator by pressing the key combination on the keyboard.
    6. To add the accelerator you have suggested for beginning and ending the recording of macros, click Add
    7. Now, in the Actions list, select Macro Playback.
    8. Repeat steps 5 and 6 to assign an accelerator for playing back the macro.
    9. Click OK.
    To record a macro:
    1. Open the source file in an editor.
    2. To begin recording, press the key combination you have defined for recording macros.
    3. Now enter the keystroke sequence you wish to record.
    4. To end recording, again press the key combination you have defined for recording macros.
    To play back a macro:
    1. Open the source file in an editor.
    2. Position your cursor in the open file.
    3. Press the key combination you have defined for playing back macros.

  2. Gather Statistics on multiple tables at once

    DESCRIPTION
    A snippet to gather stats on multiple tables (owned by your schema)

    CODE
    BEGIN FOR x IN (SELECT * FROM user_tables WHERE table_name IN (‘table1′, ‘table2′, ‘table3′))

    LOOP DBMS_STATS.gather_table_stats (ownname => USER , tabname => x.table_name , partname => NULL , estimate_percent => DBMS_STATS.auto_sample_size , block_sample => FALSE , method_opt => ‘FOR ALL INDEXED COLUMNS SIZE 254′ , degree => NULL , granularity => ‘ALL’ , cascade => TRUE , no_invalidate => FALSE );

    END LOOP;

    END;

    /

     

  3. 查找为什么某一sql 的 query rewrite 没有用

    CREATE GLOBAL TEMPORARY TABLE rewrite_table(
    STATEMENT_ID VARCHAR2(30), — id for the query
    mv_owner VARCHAR2(30), — owner of the MV
    mv_name VARCHAR2(30), — name of the MV
    SEQUENCE INTEGER, — sequence no of the error msg
    QUERY VARCHAR2(4000), — user query
    MESSAGE VARCHAR2(512), — EXPLAIN_REWRITE error msg
    pass VARCHAR2(3), — rewrite pass no
    flags INTEGER, — associated flags
    reserved1 INTEGER, — currently not used
    reserved2 VARCHAR2(10)) — currently not used
    ON COMMIT PRESERVE ROWS
    /
    – Execute anonymous block to give detailed Query Rewrite confirmation
    DECLARE
        l_stmt VARCHAR2 (4000);

        l_task_name VARCHAR2 (30);
    BEGIN
        DELETE FROM rewrite_table;
        l_stmt := ‘<< put query text here >>’;
        dbms_mview.explain_rewrite (QUERY => l_stmt , mv => ‘<>.<>’ — (or put NULL here for all MViews)
    , STATEMENT_ID => ‘MV_Explain_RW1′
    );
    END;

    /
    – Query the results
    SELECT *
    FROM rewrite_table
    ORDER BY SEQUENCE;

 

参考资料

http://htmldb.oracle.com/pls/otn/f?p=42626:54:1827078984577445::::P54_ID:341

 

http://htmldb.oracle.com/pls/otn/f?p=42626:28:1827078984577445:pg_R_1309346028248444550:NO&pg_min_row=16&pg_max_rows=15&pg_rows_fetched=15

 

http://htmldb.oracle.com/pls/otn/f?p=42626:29:1827078984577445::NO::P29_ID:401

分类: Oracle 标签:

oracle 分页排序的两种方式

2008年12月22日 没有评论

我们都知道oracle  的rownum 是一个伪列, 它会在select 之后就产生, 先于from xxx (更加不用说where xxx 和 order , group 了) , 所以如果你不排序的话,下面这种典型的oracle 分页语句是可以的:

1
2
3
4
5
SELECT * FROM 
 
(SELECT t.*,rownum row_num FROM mytable t ) b 
 
WHERE b.row_num BETWEEN 1 AND 10

或者也可以是Hibernate 里面严格的 大于 小于格式 , 记得一定要先小于.

1
2
3
4
5
SELECT * FROM 
 
(SELECT t.* , rownum FROM mytable t WHERE t.rownum&lt;100 ) b
 
WHERE b.rownum &gt; 50 .

但是如果要排序的话,由于rownum 是先于from 语句的(更加不用说where 和order 了), 所以必须要先嵌套:

排序分页的第一种方式:

1
2
3
4
5
6
7
SELECT * FROM 
 
(SELECT a.*,rownum row_num FROM 
 
SELECT * FROM mytable t ORDER BY t.id DESC) a
 
) b WHERE b.row_num BETWEEN 1 AND 10

 

另外一种就是使用minus 操作

排序分页的第二种方式

1
2
3
4
5
6
7
8
9
10
11
SELECT rownum,page.*
    FROM ( SELECT Page.*
        FROM lb_sys_twork page
            WHERE page.state=1
            ORDER BY unit_code,
            code) Page    <br />        WHERE rownum &lt; 50 MINUS SELECT rownum,page.*
        FROM ( SELECT Page.*
            FROM lb_sys_twork page
            WHERE page.state=1
            ORDER BY unit_code,
            code) Page    <br />        WHERE rownum &lt; 30

参考资料

1 . http://www.duduwolf.com/post/74.asp

    minus  方式

2. http://www.blogjava.net/joessy/articles/1398.html

    嵌套方式

分类: Database, Oracle 标签: