Oracle 11g分析表上的并发统计信息收集

前端之家收集整理的这篇文章主要介绍了Oracle 11g分析表上的并发统计信息收集前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在Oracle 11g上开发DWH.我们有一些大桌子(2.5亿行),按价值划分.每个分区被分配给不同的馈送源,每个分区独立于其他分区,因此可以同时加载和处理.

数据分布非常不均衡,我们有数百万行的分区,并且分区不超过一百行,但是我没有选择分区方案,而且我不能改变它.

考虑到数据量,我们必须确保每个分区始终保持最新的统计信息,因为如果随后的详细说明没有对数据的最佳访问权限,那么它们将永远持续下去.

所以对于每个并发ETL线程,我们

>截断分区
>从分段区域加载数据

SELECT / * APPEND * / INTO big_table PARTITION(part1)FROM temp_table WHERE partition_colum = PART1

(这样我们有直接的路径,我们不锁定整个表)

>我们收集修改分区的统计信息.

在项目的第一阶段,我们使用了APPROX_GLOBAL_AND_PARTITION策略,像一个魅力

dbms_stats.gather_table_stats(ownname=>myschema,tabname=>big_table,partname=>part1,estimate_percent=>1,granularity=>'APPROX_GLOBAL_AND_PARTITION',CASCADE=>dbms_stats.auto_cascade,degree=>dbms_stats.auto_degree)

但是,我们有一个缺点,当我们加载一个小分区时,APPROX_GLOBAL部分占主导地位(仍然比GLOBAL快得多),而对于一个小分区,我们有例如10秒的加载和20分钟的统计信息.

因此,我们建议您切换到11g的INCREMENTAL STATS功能,这意味着您不要指定已修改的分区,您将所有参数都保留在auto中,而且Oracle具有魔力,自动了解哪个分区被感动.它实际上是有效的,我们真的加快了小分区.打开功能后,呼叫成为

dbms_stats.gather_table_stats(ownname=>myschema,estimate_percent=>dbms_stats.auto_sample_size,granularity=>'AUTO',degree=>dbms_stats.auto_degree)

请注意,您不再传递分区,并且不指定样本百分比.

但是,也许比以前更糟糕,这与我们拥有的高水平的并行性相关.

假设我们有两个大的分区同时启动,几乎同时完成加载阶段.

>第一个线程结束insert语句,提交并启动统计信息.统计程序注意到修改了2个分区(这是正确的,一个是完整的,第二个被截断,一个事务正在进行中),正确地更新两个分区的统计信息.
>最终第二个分区结束,收集统计信息,看到所有的分区已经被更新,并且什么都不做(这是不正确的,因为第二个线程同时提交了数据).

结果是:

PARTITION NAME | LAST ANALYZED        | NUM ROWS | BLOCKS | SAMPLE SIZE
-----------------------------------------------------------------------
PART1          | 04-MAR-2015 15:40:42 | 805731   | 20314  | 805731
PART2          | 04-MAR-2015 15:41:48 | 0        | 16234  | (null)

结果是我偶尔会出现不是最佳的计划(这意味着杀死会话,手动刷新统计信息,再次手动启动进程).

我甚至尝试在集会上放置专属锁,所以只有一个线程可以同时在同一张桌子上收集统计信息,但没有改变.

IMHO这是一个奇怪的行为,因为统计过程,第二次被调用,应该检查第二个分区上的最后一个提交,并应该看到它比最后的统计信息的时间更新.但似乎没有发生.

我做错了吗?这是一个Oracle bug吗?如何保证所有的统计信息始终是最新的增量统计功能开启,以及高水平的并发性?

我设法通过这个功能达成一个合理的妥协.
PROCEDURE gather_tb_partiz(
    p_tblname IN VARCHAR2,p_partname IN VARCHAR2)
IS
  v_stale all_tab_statistics.stale_stats%TYPE;
BEGIN
  BEGIN
    SELECT stale_stats
    INTO v_stale
    FROM user_tab_statistics
    WHERE table_name = p_tblname
    AND object_type = 'TABLE';
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
    v_stale := 'YES';
  END;
  IF v_stale = 'YES' THEN
    dbms_stats.gather_table_stats(ownname=>myschema,tabname=> p_tblname,partname=>p_partname,degree=>dbms_stats.auto_degree,granularity=>'APPROX_GLOBAL AND PARTITION') ;
  ELSE
    dbms_stats.gather_table_stats(ownname=>myschema,tabname=>p_tblname,granularity=>'PARTITION') ;
  END IF;
END gather_tb_partiz;

在每个ETL的末尾,如果添加/删除/修改的行的数量足够低,不能将表标记为过时(默认为10%,可以使用STALE_PERCENT参数进行调整),我仅收集分区统计信息;否则我收集全局和分区统计信息.

这样可以快速维护小型分区的ETL,因为不必全局分区,而且大分区也是安全的,因为随后的任何查询都将具有新的统计信息,并且可能会使用最优的计划.

无论如何启用增量统计信息,所以无论何时必须重新计算全局值,它都非常快,因为聚合了分区级统计信息,并且不执行全面扫描.

我不知道如果增量启用,“APPROX_GLOBAL AND PARTITION”和“GLOBAL AND PARTITION”与“GLOBAL AND PARTITION”的区别在于,因为增量和大约都基本相同:聚合统计数据和直方图,而不进行全面扫描.

猜你在找的Oracle相关文章