2014-01-21 26 views
2

我有5個開發模式。他們每個人都有分區表。我們還有腳本來動態創建分區表(每月/每年)。我們必須每次都去DBA收集分區表上的細節。我們真正的問題是我們有一個有9個分區的分區表。在增量加載操作(更新/刪除使用PL/SQL)之後的每一天,也使用SQL*Loader加載一些APPEND加載。此操作在數據庫具有峯值負載時發生。 (SELECT查詢)確定在模式列表中具有陳舊統計信息的分區

當向DBA報告時,他們會說表格統計信息已過時,並且在他們「收集統計信息」之後,奇蹟般地查詢起作用更快。我搜索了這個,並確定了一些關於dynamic performance的意見。

所以,現在,我有以下問題。

1)開發人員是否可以生成所有分區表的列表,分區名稱,沒有可用的記錄,而無需轉到DBA?
2)我們是否應該確定每個parition的最後分析日期
3)parition(index)的狀態是否可用或不可用。

回答

0

我用來查詢下面提到ALL_表。

您提到的統計信息和直方圖細節將由Oracle自動更新一個頻率。但是當數據庫忙於許多負載時,我看到這些操作需要手動觸發。我們面臨類似的情況,因此我們過去在加載關鍵表之後強制執行分析操作。您需要有用於加載表的id的特權。

ANALYZE TABLE table_name PARTITION (partition_name) COMPUTE STATISTICS; 

編輯ANALYZE不再收集CBO統計提到here

所以,DBMS_STATS包已被使用。

DBMS_STATS.GATHER_TABLE_STATS (
    ownname   VARCHAR2, 
    tabname   VARCHAR2, 
    partname   VARCHAR2 DEFAULT NULL, 
    estimate_percent NUMBER DEFAULT to_estimate_percent_type 
               (get_param('ESTIMATE_PERCENT')), 
    block_sample  BOOLEAN DEFAULT FALSE, 
    method_opt  VARCHAR2 DEFAULT get_param('METHOD_OPT'), 
    degree   NUMBER DEFAULT to_degree_type(get_param('DEGREE')), 
    granularity  VARCHAR2 DEFAULT GET_PARAM('GRANULARITY'), 
    cascade   BOOLEAN DEFAULT to_cascade_type(get_param('CASCADE')), 
    stattab   VARCHAR2 DEFAULT NULL, 
    statid   VARCHAR2 DEFAULT NULL, 
    statown   VARCHAR2 DEFAULT NULL, 
    no_invalidate BOOLEAN DEFAULT to_no_invalidate_type (
            get_param('NO_INVALIDATE')), 
    force   BOOLEAN DEFAULT FALSE); 

而直到分析完成後,查看錶格下方可能不會產生準確的結果(特別是LAST_ANALYZED和NUM_ROWS列)

注:嘗試在表名稱替換all_dba_,如果你有訪問它,你可以嘗試它們。

您也可以嘗試讓SELECT_CATALOG_ROLE爲你使用開發的ID,這樣您就可以選擇data dictionary views,這降低了DBA過這樣的查詢的相關性。(還有DBA是幾個問題權的人!)

查詢以識別分區表,分區名稱,行數和上次分析日期!

select 
     all_part.owner as schema_name, 
     all_part.table_name, 
     NVL(all_tab.partition_name,'N/A'), 
     all_tab.num_rows, 
     all_tab.last_analyzed 
from 
     all_part_tables all_part, 
     all_tab_partitions all_tab 
where all_part.table_name = all_tab.table_name and 
     all_tab.partition_name = all_tab.partition_name and 
     all_part.owner=all_tab.table_owner and 
     all_part.owner in ('SCHEMA1','SCHEMA2','SCHEMA3') 
order by all_part.table_name,all_tab.partition_name; 

以下查詢返回是UNUSABLE

SELECT INDEX_NAME, 
    TABLE_NAME, 
    STATUS 
FROM ALL_INDEXES 
WHERE status NOT IN ('VALID','N/A'); 

以下查詢返回的索引/表是UNUSABLE

SELECT INDEX_NAME, 
    PARTITION_NAME, 
    STATUS , 
    GLOBAL_STATS 
FROM ALL_IND_PARTITIONS 
WHERE status != 'USABLE'; 
+1

DBMS_STATS可能會比[ANALYZE](http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_4005.htm#SQLRF01105)更好。 –

+0

我同意@jonearles,這也是一個一般性建議。您不應該使用'ANALYZE'來收集Oracle 8i後的統計信息,而應該使用DBMS_STATS。您可以查看http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:247162600346210706也 – Incognito

+0

謝謝@jonearles和隱身,我編輯了我的答案。 –

1
  1. 是的,你可以生成分區表的列表,和大量的相關數據,你想看到的,通過使用ALL_PART_TABLESUSER_PART_TABLES(只要你有訪問)。 ALL_TAB_PARTITIONS可用於獲取每個分區的行數以及其他詳細信息。

查看其他視圖Oracle收集有關分區表的詳細信息。

  1. 我建議你應該在你的數據加載後每天分析表,並且可能重建索引。如果您的數據加載影響表中的許多記錄,並且將影響現有索引,則主動更新表和索引的統計信息是一個好主意。

  2. 您可以使用該系統的觀點來獲取此信息(請http://docs.oracle.com/cd/E18283_01/server.112/e16541/part_admin005.htm

2

正常情況(PARTITION)名稱的索引/表名無需識別需要收集統計信息的對象。 Oracle自動收集過時對象的統計信息,除非手動禁用任務 。對於OLTP系統來說,這通常足夠好。使用此查詢來查找任務的狀態:

select status 
from dba_autotask_client 
where client_name = 'auto optimizer stats collection'; 

STATUS 
------ 
ENABLED 

對於數據倉庫系統還存在沒有太大的必要查詢數據字典陳舊的統計數據。在數據倉庫統計中幾乎需要考慮每個操作的 。開發人員需要養成在截斷,插入,交換等操作後始終考慮統計信息的習慣。最終,他們將「只知道」何時收集統計信息。

但是,如果您仍想查看Oracle如何確定統計數據是否陳舊,請查看DBA_TAB_STATISTICSDBA_TAB_MODIFICATIONS

下面是一個使用統計信息收集的初始加載示例。表和分區不陳舊。

create table test1(a number, b number) partition by list(a) 
(
    partition p1 values (1), 
    partition p2 values (2) 
); 
insert into test1 select 1, level from dual connect by level <= 50000; 
begin 
    dbms_stats.gather_table_stats(user, 'test1'); 
    dbms_stats.flush_database_monitoring_info; 
end; 
/

select table_name, partition_name, num_rows, last_analyzed, stale_stats 
from user_tab_statistics 
where table_name = 'TEST1' 
order by 1, 2; 

TABLE_NAME PARTITION_NAME NUM_ROWS LAST_ANALYZED STALE_STATS 
---------- -------------- -------- ------------- ----------- 
TEST1  P1     50000  2014-01-22   NO 
TEST1  P2      0  2014-01-22   NO 
TEST1       50000  2014-01-22   NO 

現在添加大量的行並且統計數據是陳舊的。

begin 
    insert into test1 select 2, level from dual connect by level <= 25000; 
    commit; 
    dbms_stats.flush_database_monitoring_info; 
end; 
/

select table_name, partition_name, num_rows, last_analyzed, stale_stats 
from user_tab_statistics 
where table_name = 'TEST1' 
order by 1, 2; 

TABLE_NAME PARTITION_NAME NUM_ROWS LAST_ANALYZED STALE_STATS 
---------- -------------- -------- ------------- ----------- 
TEST1  P1     50000  2014-01-22   NO 
TEST1  P2      0  2014-01-22   YES 
TEST1       50000  2014-01-22   YES 

USER_TAB_MODIFICATIONS給出關於表陳舊度的更具體的信息。

--Stale statistics. 
select user_tables.table_name, user_tab_modifications.partition_name 
    ,inserts+updates+deletes modified_rows, num_rows, last_analyzed 
    ,case when num_rows = 0 then null 
     else (inserts+updates+deletes)/num_rows * 100 end percent_modified 
from user_tab_modifications 
join user_tables 
    on user_tab_modifications.table_name = user_tables.table_name 
where user_tables.table_name = 'TEST1'; 

TABLE_NAME PARTITION_NAME MODIFIED_ROWS NUM_ROWS LAST_ANALYZED PERCENT_MODIFIED 
---------- -------------- ------------- -------- ------------- ---------------- 
TEST1  P2      25000  50000  2014-01-22    50 
TEST1        25000  50000  2014-01-22    50 
1

我有一些什麼類似的問題,我只用11克新INCREMENTAL選項收集陳舊的分區統計解決它。

這是你的問題的反向方法,但它可能值得研究(具體 - 甲骨文如何確定什麼是「陳舊」的分區)。

dbms_stats.set_table_prefs('DWH','FACT_TABLE','INCREMENTAL','TRUE') 

我總是喜歡親積極的方法 - 這意味着,在我的ETL的最後一步收集陳舊分區統計,而不是讓開發商更強PRIVS。