我有表ABC每天的時間間隔分區。每個分區都用於特定日期的查詢。即使我每天安排job @nyt來收集統計信息,那麼在統計信息收集之前使用該表的查詢將不會使用最佳計劃。收集分區表上的統計信息
回答
收集分區表上的優化程序統計信息並不是一件簡單的任務,但有一些注意事項。 特別是在日常分區模式下,它可能不是每天收集一次分區統計數據的最佳解決方案。
爲了演示它,假設我們沒有每日模式,但每年的事務數據分區。問題是, 可以在1月1日(或1月1日或12月31日)收集統計數據嗎? 答案是肯定沒有,因爲在第一種情況下分區將被認爲(幾乎)爲空,在後面的情況下 統計將是現實的,但是它們被收集得太遲。
考慮到這一點有IMO三種到處理它
1)不要聚集在所有的統計數據(並使用動態採樣)
2)反覆收集分區統計可能的方法(比如每個小時)
3)不收集統計數據,但將它們設置是這樣,查詢進行精細
最好的選擇取決於您的數據和訪問模式,所以我只考慮一些細節,那些選擇實施離子。
樣本數據
允許生成一個完整的和一個幾乎空日常分區的表。
該表在GROUP_ID
列中有一個本地索引。練習的目的是在訪問小分區時獲取FULL TABLE SCAN
,並在訪問大分區時獲取INDEX ACCESS
。
CREATE TABLE mytab
( id number not null,
group_id number,
trans_date date,
pad varchar2(4000))
PARTITION BY RANGE (trans_date)
INTERVAL (NUMTODSINTERVAL(1,'DAY'))
(
PARTITION part_01 values LESS THAN (TO_DATE('31-12-2016','DD-MM-YYYY'))
);
create index mytab_idx1 on mytab(id) local;
create index mytab_idx2 on mytab(group_id) local;
-- full day partition
insert into mytab (id, group_id, trans_date, pad)
select rownum id, trunc(rownum/1000) group_id, to_date('31122016','ddmmyyyy'), lpad('x',3000,'x') from dual
connect by level <= 100000;
commit;
-- nearly empty day partition
insert into mytab (id, group_id, trans_date, pad)
select rownum id, trunc(rownum/1000) group_id, to_date('01012017','ddmmyyyy'), lpad('x',3000,'x') from dual
connect by level <= 1000;
commit;
動態採樣
如果目標對象沒有統計可言,Oracle執行動態採樣(又名dynamic statistics) 有了一個小的開銷甲骨文計算統計數據,而解析的語句。所以它不能陳舊。
訪問幾乎是空的分區甲骨文適當選擇FULL TABLE SCAN
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
select * from mytab
where trans_date = TO_DATE('01-01-2017','DD-MM-YYYY') and group_id = 0;
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
Plan hash value: 4018216072
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 958 | 1905K| 274 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE| | 958 | 1905K| 274 (0)| 00:00:01 | 3 | 3 |
|* 2 | TABLE ACCESS FULL | MYTAB | 958 | 1905K| 274 (0)| 00:00:01 | 3 | 3 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("TRANS_DATE"=TO_DATE(' 2017-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
AND "GROUP_ID"=0)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
...在訪問完整的分區INDEX ACCESS
用於
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
select * from mytab
where trans_date = TO_DATE('31-12-2016','DD-MM-YYYY') and group_id = 0;
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
Plan hash value: 984912596
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1608 | 3198K| 9021 (1)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 1608 | 3198K| 9021 (1)| 00:00:01 | 2 | 2 |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| MYTAB | 1608 | 3198K| 9021 (1)| 00:00:01 | 2 | 2 |
|* 3 | INDEX RANGE SCAN | MYTAB_IDX2 | 1608 | | 2880 (1)| 00:00:01 | 2 | 2 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("TRANS_DATE"=TO_DATE(' 2016-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
3 - access("GROUP_ID"=0)
Note
-----
- dynamic statistics used: dynamic sampling (level=2)
所以我們看到,動態採樣工作正常,選擇正確的訪問方法。
收集分區統計經常
重複採集工作減輕了問題,該分區在不斷增加。
期限取決於交易利率。
對一個分區僅
exec dbms_stats.gather_table_stats(OWNNAME=>user,TABNAME=>'MYTAB', PARTNAME=>'SYS_P10030', CASCADE=> TRUE);
必須避免最壞的情況收集統計數據的例子是*統計指向該分區是空的,但(在此期間)的分區是重填充。
設置統計
這種方法假定,對於查詢「正確」的訪問路徑是已知的。在我們的示例 中,我們可以訪問幾乎爲空的分區,其中FULL TABLE SCAN
,但對於此類分區 也可以使用索引訪問。因此,我們可以設置分區統計信息,以便始終進行INDEX ACCESS。
一個可能的(非常簡單的)模式是複製前一天的統計數據。
這個調用拷貝從分區SYS_P10029
統計分區SYS_P10030
exec DBMS_STATS.COPY_TABLE_STATS (OWNNAME=>user,TABNAME=>'MYTAB',srcpartname=>'SYS_P10029',dstpartname=> 'SYS_P10030');
所以換句話說,創立了統計開始爲充分填充分區的分區之後立即執行。
在我的應用程序中,我每天通過調度程序作業來運行此過程。它收集最近分區的統計信息。
PROCEDURE GatherIndexStats IS
CURSOR IndexPartition(indName IN VARCHAR2) IS
SELECT INDEX_NAME, PARTITION_NAME
FROM USER_IND_STATISTICS i
JOIN USER_TAB_PARTITIONS t USING (TABLE_NAME, PARTITION_NAME)
WHERE TABLE_NAME = 'ABC'
AND i.LAST_ANALYZED IS NULL
AND OBJECT_TYPE = 'PARTITION'
AND INDEX_NAME = indName
ORDER BY INDEX_NAME, PARTITION_NAME DESC
OFFSET 1 ROW FETCH FIRST 2 ROW ONLY;
BEGIN
FOR aIndex IN (SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME = 'ABC') LOOP
FOR aInd IN IndexPartition(aIndex.INDEX_NAME) LOOP
DBMS_STATS.GATHER_INDEX_STATS(USER, aInd.INDEX_NAME, aInd.PARTITION_NAME);
END LOOP;
END LOOP;
END GatherIndexStats;
在我的應用程序需要得到唯一索引統計信息,而不是完整的表的統計信息。如果您想獲得索引和表格統計信息,請使用以下步驟:
PROCEDURE GatherTableStats IS
CURSOR TablePartition IS
SELECT INDEX_NAME, PARTITION_NAME
FROM USER_TAB_STATISTICS i
JOIN USER_TAB_PARTITIONS t USING (TABLE_NAME, PARTITION_NAME)
WHERE TABLE_NAME = 'ABC'
AND i.LAST_ANALYZED IS NULL
AND OBJECT_TYPE = 'PARTITION'
ORDER BY PARTITION_NAME DESC
OFFSET 1 ROW FETCH FIRST 2 ROW ONLY;
BEGIN
FOR aPart IN TablePartition LOOP
DBMS_STATS.GATHER_TABLE_STATS(USER, 'ABC', aPart.PARTITION_NAME);
END LOOP;
END GatherTableStats;
統計信息應作爲任何過程的一部分收集,以顯着更改數據。不要依賴夜間工作來收集統計數據,特別是在大型數據倉庫中。
收集統計信息只在夜間的工作有許多潛在的缺點:
- 的處理有一個奇怪的時間依賴性。統計窗口可能會很難協調。有時如果工作太多,你關心的桌子可能沒有時間進行分析。
- 有幾種類型的統計作業(調度程序作業,DBA_JOBS,auto_tasks),所有這些類型都傾向於禁用更多的應用程序。
- 收集統計在錯誤的時間是差很多比根本沒有統計。如果沒有統計數據,那麼Oracle可以使用動態採樣來做一份體面的工作。但是,如果夜間工作恰好在表格爲空的短暫時間內收集統計數據,則統計數據可能會非常錯誤,並且性能將受到影響。我見過這種事多次發生;這些錯誤往往被歸咎於「環境差異」,但如果你離開關鍵的一步,那麼環境將隨機失敗。
作爲數據加載過程的一部分收集統計信息有許多潛在的優勢。既然你瞭解過程和表比一些普通的晚間統計工作,你可以採取的許多先進的功能優勢更好:
- 如果系統不是數據負載,然後並行可以像參數一起使用後忙度=> 8。
- 如果它是12c中的直接路徑寫入,則可以在使用GATHER_OPTIMIZER_STATISTICS提示加載數據時自動收集統計信息。
- 如果是間隔分區表,則可能需要設置增量統計信息收集。這使得該進程只花費時間收集分區的統計信息,並且全局統計信息將免費更新。
- 如果進程禁用並重建索引,則可以避免使用參數NOCASCADE => TRUE重新收集索引統計信息。
不要外包統計收集到其他計劃的工作。統計數據非常重要且棘手,應該與任何正在進行重大數據更改的程序完全集成。
- 1. 收集有關Oracle中子分區表的統計信息
- 2. Postgres統計信息收集
- 3. 收集mysql統計信息
- 4. Oracle 12c:僅收集新分區的統計信息
- 5. Oracle統計信息收集表
- 6. Python收集系統統計信息
- 7. oracle中的統計信息收集
- 8. 如何收集統計信息
- 9. 攔截LDAP以收集統計信息
- 10. 收集站點用戶統計信息
- 11. MySQL分區使用統計信息
- 12. 收集索引上的統計信息或刪除創建?
- 13. Lcov:無法收集分支機構覆蓋率統計信息
- 14. 在Rails 3.1中進行統計信息收集(分析)
- 15. 對運營統計信息收集系統的建議
- 16. 在asp.net mvc網站上收集統計信息?
- 17. 表統計信息收集期間'輸入值無效'?
- 18. 在過程中包含表收集統計信息
- 19. 收集oracle使用情況統計信息(查看哪些表)
- 20. 如何收集有關java集成測試的統計信息
- 21. Elasticsearch Marvel未收集Windows操作系統統計信息
- 22. 收集表統計和計算統計
- 23. 收集客戶端計算機和瀏覽器統計信息
- 24. Oracle計算實際使用大小和統計信息收集
- 25. 收集所有運行的shell腳本的統計信息
- 26. 用於性能評估的java統計信息收集
- 27. 收集NTFS文件訪問統計信息的最佳方法?
- 28. API從運行的JVM收集統計信息
- 29. 收集ejabberd中的特定組件統計信息
- 30. 如何重置MongoDB的收集統計信息?
添加查詢計劃和ddl –
每當添加新分區並且存在大量數據加載時,我想知道我們是否具有自動收集的統計信息。如果沒有,那麼我們如何收集統計信息? – oracle
看看包DBMS_STATS.GATHER_TABLE_STATISTICS,在那裏你也可以指定分區。 –