2016-09-27 103 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;