Oracle 所有分区的cific时间间隔,而不是在加载每个分区的进程结束时。如果这是一个活动表,并且24小时都有恒定的数据负载,这可能是一个挑战,但由于这些是大型DW表,我真的怀疑情况是否如此。因此,最好的办法是在加载所有分区结束时收集统计信息,这将确保为数据发生更改或统计信息丢失的分区收集统计信息,并根据分区级别的统计信息和概要信息更新全局统计信息

Oracle 所有分区的cific时间间隔,而不是在加载每个分区的进程结束时。如果这是一个活动表,并且24小时都有恒定的数据负载,这可能是一个挑战,但由于这些是大型DW表,我真的怀疑情况是否如此。因此,最好的办法是在加载所有分区结束时收集统计信息,这将确保为数据发生更改或统计信息丢失的分区收集统计信息,并根据分区级别的统计信息和概要信息更新全局统计信息,oracle,oracle11g,etl,data-warehouse,table-statistics,Oracle,Oracle11g,Etl,Data Warehouse,Table Statistics,然而,要做到这一点,您需要为表(11gR1)启用增量特性 EXEC DBMS_STATS.SET_TABLE_PREFS(“”,'BIG_TABLE','INCREMENTAL','TRUE') 在每次加载结束时,使用gather\u table\u STATS命令收集表统计信息。您不需要指定分区名称。另外,不要指定粒度参数 EXEC DBMS_STATS.GATHER_TABLE_STATS(“”,'BIG_TABLE')我设法用这个函数达成了一个不错的折衷方案 PROCEDURE gathe

然而,要做到这一点,您需要为表(11gR1)启用增量特性

EXEC DBMS_STATS.SET_TABLE_PREFS(“”,'BIG_TABLE','INCREMENTAL','TRUE')

在每次加载结束时,使用
gather\u table\u STATS
命令收集表统计信息。您不需要指定分区名称。另外,不要指定粒度参数


EXEC DBMS_STATS.GATHER_TABLE_STATS(“”,'BIG_TABLE')

我设法用这个函数达成了一个不错的折衷方案

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,
                                 partname=>p_partname,
                                 degree=>dbms_stats.auto_degree,
                                 granularity=>'PARTITION') ;
  END IF;
END gather_tb_partiz;
在每个ETL结束时,如果添加/删除/修改的行数足够少,以至于无法将表标记为过时(默认情况下为10%,可以使用stale_PERCENT参数进行调整),则我只收集分区统计信息;否则,我收集全局和分区统计信息

这使小分区的ETL保持快速,因为不需要重新聚集全局分区,而大分区是安全的,因为任何后续查询都会有新的统计信息,并且可能会使用最佳计划

不管怎样,增量统计都是启用的,因此每当需要重新计算全局数据时,它的速度相当快,因为它会聚合分区级别的统计数据,并且不会执行完全扫描


我不确定,在启用增量的情况下,“近似全局和分区”和“全局和分区”是否在某些方面有所不同,因为增量和近似都做基本相同的事情:在不进行完全扫描的情况下聚合统计数据和直方图。

我以某种方式尝试序列化分区加载。我在做一个没有指定分区的+APPEND(我错了),这导致整个表被锁定,所以实际上不能有多个线程同时在同一个表上加载数据。但由于我们有16个多小时的进程,序列化(使用10个并发线程)并不是一种可行的方法。我们的流程有非常严格的截止日期。关于日志记录,据我所见,所有表都已处于日志记录模式,我无法对其进行任何更改;结束。表修改数据似乎有一些脏读在进行——多个会话相互看到未提交的插入,一个会话可以清除所有会话的数据。我不认为这是特定于增量统计的。它可能有助于在调用
DBMS\u STATS
之前插入和删除一个虚拟行,以帮助强制收集。我想发布更多信息,但我现在没有足够的时间给出完整的答案。不幸的是,我没有DBA权限,甚至连表所有者都没有。顺便说一句,文档中说“因为GATHER_*u STATS过程在内部刷新监控信息,所以在收集统计数据之前不必运行此过程。”我正在尝试只收集分区级别的统计数据(有效),并偶尔刷新全局数据,以避免此问题,直到我找到一个最终的解决方案。你应该提供更多的细节。什么时候开始插入?在可疑盗窃统计数据插入开始之前或之后?他们中的哪一个先完成插入?你花了多少时间来做这件事?收集偷窃数据要花多少时间?可能第一个分区上的收集正在进行,而第二个会话正在提交?第一个分区上的收集将在第二个分区仍在插入时启动。是否为表启用了增量维护功能?比如
execdbms\u STATS.SET\u TABLE\u PREFS(“”,'BIG\u TABLE','INCREMENTAL','TRUE')我试过了,考虑到所花费的时间,它的行为似乎类似于“全局和分区”。但我会再检查一遍。不,我错了。未指定粒度默认为“自动”,这将覆盖partname的存在。他正在收集所有被触摸分区的统计数据,即使指定了partname,我也只是验证了它。如果统计数据正在运行并且分区被修改了,它不会收集新的统计数据,那么它看起来像一个错误。是的,我做了。我检查了增量统计的所有先决条件是否都满足。我采用了类似的解决方案。在每次ETL加载之后,我检查全局统计数据是否过时,如果过时,我收集分区和全局,否则只收集分区。这提供了很好的性能,因为当我加载小分区时,它改变的行数不超过总行数的10%,也不需要更新全局。我无法遵循您的解决方案。正如我在最初的文章中所说的,每个表的每个分区都是独立于其他分区的,我们具有高度的并行性。一旦分区A加载到表1中,数据就开始处理并向前移动到表1(具有相同的分区A)。同时,我们可以接收partitionB,它必须以相同的方式同时加载和处理。我不能等待TabL1被完全加载和分析,我会浪费太多的时间。嗯,我认为你应该考虑收集统计数据,如果它们过时。在每次加载之后收集每个分区上的统计数据对我来说似乎有点过分,除非您是在9i或其他版本中,或者试图补偿处理这些数据的代码,并且编写得很糟糕。
 dbms_stats.gather_table_stats(ownname=>myschema,
                              tabname=>big_table,
                              estimate_percent=>dbms_stats.auto_sample_size,
                              granularity=>'AUTO',
                              CASCADE=>dbms_stats.auto_cascade,
                              degree=>dbms_stats.auto_degree) 
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)
 dbms_stats.gather_table_stats(ownname=>myschema,
                              tabname=>big_table,
                              partname=>part,
                              degree=>dbms_stats.auto_degree);
BEGIN 
DBMS_STATS.SET_TABLE_PREFS(myschema,'BIG_TABLE','INCREMENTAL','TRUE'); 
END;
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,
                                 partname=>p_partname,
                                 degree=>dbms_stats.auto_degree,
                                 granularity=>'PARTITION') ;
  END IF;
END gather_tb_partiz;