2016-09-27 119 views
1

我最近将Oracle 12c中的几个大型表转换为日期字段和分区索引上的每日区间范围分区。作为数据加载过程的一部分,我在数据插入并提交后在表格末尾执行收集统计过程。当插入的新数据不属于任何现有分区的上限时,新的分区会自动创建,因此时间间隔分区更容易。但是,我注意到执行收集统计过程所花的时间非常长,对于行数超过1亿的表需要花费很多时间。问题是:大部分数据没有改变,所以我只想收集新的分区或数据已经改变的分区的统计信息。有没有办法可以做到这一点?Oracle 12c:仅收集新分区的统计信息

+0

您可以简单复制统计纳入新的分区形式,以前的完全分区。 –

回答

1

这正是incremental statistics的目的。

使用增量统计信息,Oracle仅收集已更改分区的分区统计信息。 Synopses是为每个分区构建的,并且这些提要可以快速组合起来创建全局统计信息,而无需重新扫描整个表格。

要启用它,只需设置表格首选项并收集统计信息。第一次聚会会很慢,但未来的统计收集速度会更快。

begin 
    dbms_stats.set_table_prefs('TABLE_OWNER', 'TABLE_NAME', 'incremental', 'true'); 
    dbms_stats.gather_table_stats('TABLE_OWNER', 'TABLE_NAME'); 
end; 
/
2

你在这里。通过分区值收集统计信息的脚本。也许它可以帮助你:

declare 
    v_table_name varchar2(64) := ''; --your table 
    v_key_value number := ; -- your range value 

    v_data_object_id number; 
    v_object_name varchar2(64); 
    v_object_type varchar2(64); 
    v_granularity varchar2(64); 
    v_part_name varchar2(64); 
begin 
    begin 
    for i in (select kc.column_name 
       from user_part_key_columns kc 
       where kc.name = upper(v_table_name) 
       and kc.object_type = 'TABLE') 
    loop 
     execute immediate 'select /*+ first_rows */ dbms_rowid.rowid_object(rowid) 

          from ' || v_table_name || ' 
          where '|| i.column_name || ' = '|| v_key_value || 
          ' and rownum = 1' 
     into v_data_object_id; 
    end loop; 
    exception 
    when no_data_found then 
     v_data_object_id := null; 
    end; 

    begin 
    select t.subobject_name, t.OBJECT_TYPE 
     into v_object_name, v_object_type 
    from user_objects t 
    where t.data_object_id = v_data_object_id; 
    exception 
     when no_data_found then 
     v_object_name := null; 
    end; 

    if v_object_name is null 
    then 
     dbms_output.put_line ('no data found'); 
    else 
     if v_object_type = 'TABLE SUBPARTITION' 
     then 
      v_granularity := 'SUBPARTITION'; 

      select t.partition_name 
      into v_part_name 
      from user_tab_subpartitions t 
      where t.subpartition_name = v_object_name; 

     else 
      v_granularity := 'PARTITION'; 
      v_part_name := v_object_name; 
     end if; 

     dbms_stats.gather_table_stats (ownname => user 
            ,tabname => upper(v_table_name) 
            ,partname => v_part_name 
            ,granularity => v_granularity 
            ,cascade => true 
            ,no_invalidate => false); 
    end if; 
end; 
0

另一种简单的解决办法是这样:

BEGIN 
FOR aPart IN (SELECT TABLE_NAME, PARTITION_NAME FROM USER_TAB_PARTITIONS WHERE TABLE_NAME = 'YOUR_TABLE' AND LAST_ANALYZED IS NULL) LOOP 
    DBMS_STATS.GATHER_TABLE_STATS(USER, aPart.TABLE_NAME, aPart.PARTITION_NAME); 
END LOOP; 
END;