2009-06-11 56 views
6

我們有成熟的Oracle數據庫應用程序(在生產超過10年),在此期間,我們已經用我們自己設計的腳本來刪除不再需要的舊數據了。他們通過在頻繁提交的循環中針對適當的表發佈刪除語句來工作,以避免使用I/O或使用太多撤銷空間來重載系統。技術在Oracle中刪除舊數據的數據庫

他們工作得很好,大部分。它們每天都在運行,大約需要一個小時才能從系統中刪除最舊的數據。我所關心的主要問題是所有這些刪除操作可能會對錶和索引產生影響,即使它們不會過度加載系統,但在短時間內刪除一天的數據也會產生影響取出實例緩衝區緩存,導致後續查詢在接下來的幾個小時內運行速度稍慢,因爲緩存正在逐漸恢復。

多年來,我們一直在考慮更好的方法。在過去,我聽說人們使用分區表來管理舊數據收割 - 例如每個分區一個月,並且每月刪除最老的分區。這種方法的主要缺點是我們的收割規則超越了「去除X月」的問題。允許用戶根據關鍵值指定數據保留在系統中的時間(例如,在發票表中,賬戶foo可以在3個月後被移除,但賬戶欄可能需要保留2年)。

也有引用完整性的問題; Oracle文檔討論瞭如何使用分區來清除主要在數據倉庫環境中的數據,其中表往往是超立方體。我們更接近OLTP結束的事情,並且X月的數據與Y月的數據有關係很常見。爲這些表創建正確的分區鍵最多隻會發癢。對於高速緩存爆炸,我已經讀了一些關於設置專用緩衝區高速緩存的內容,但似乎更多的是基於每個表的基礎,而不是每個用戶或每個事務的基礎。爲了保留緩存,我真的很喜歡收穫工作,因爲在任何時候只保留緩存中一筆交易的數據,因爲一旦刪除數據就不需要保留數據。

是我們堅持使用刪除可預見的未來,還是有其他的,更聰明的方式來處理與收穫?

+0

+1很好的問題,希望我有一個聰明的解決方案,因爲我可以用它自己;-) – DCookie 2009-06-11 15:41:10

+0

是保持數據不是一個選項?即您可以過濾查詢中的舊記錄(例如,使用VPD謂詞)並且不返回舊記錄。只是說,如果刪除行導致性能問題,我至少會考慮保留它們的可能性不一定是更糟糕的情況。 – 2013-06-19 06:14:23

回答

4

大多數情況下,我認爲你被困在做刪除。

您對在您的案例中使用分區困難的評論可能會阻止它們被有效使用(根據記錄類型使用不同的刪除日期),但是您可能會創建一個「刪除日期」列您可以劃分的記錄?由於刪除日期的更改可能會導致行遷移,因此它的缺點是使更新非常昂貴,因此您的更新實際上會作爲刪除和插入來實施。

可能是由於參照完整性問題,即使不能使用DDL分區操作來刪除舊數據,但分區仍然可以達到物理集羣要刪除的行的目的,從而需要修改更少的塊爲了刪除它們,減輕對緩衝區緩存的影響。

0

刪除的也不差,只要你重建索引。 Oracle將恢復不再包含數據的頁面。

但是,至於8i(很可能還是),它不會正確地恢復不再包含有效引用的索引頁。更糟糕的是,由於索引葉片被鏈接起來,您可能會陷入一種情況,它將開始走葉節點以查找一行。這會導致性能顯着下降:通常需要幾秒鐘的查詢可能需要幾分鐘的時間。下降也非常突然:有一天它會沒事,第二天它不會。

我發現這種行爲(有一個Oracle的錯誤,所以其他人也有)使用增加的鍵和定期刪除的數據的應用程序。我們的解決方案是顛倒鍵的一部分,但這不會幫助你的日期。

0

如果您暫時停用索引,執行刪除操作並重建它們,該怎麼辦?它會提高刪除的性能嗎?當然,在這種情況下,您必須確保腳本正確並確保正確的刪除順序和參照完整性。

0

我們有同樣的問題,使用相同的策略。 如果情況變得非常糟糕(索引,表格分配非常分散),我們嘗試應用空間回收操作。

表必須允許行移動(如閃回): alter table TTT啓用行移動; 改變表TTT收縮空間; ,然後重建所有索引。

我不知道你是如何與維護窗口,如果應用程序必須始終可用,它是困難的,如果不是,你可以做一些「重新包裝」,當它離線。 「改變表TTT移動表空間SSSS」在重寫表時會做很多工作來清理混亂。您還可以指定新的存儲參數,例如擴展區管理,大小,......查看文檔。

我用這樣的腳本來爲整個數據庫創建腳本:

SET SQLPROMPT "-- " 
SET ECHO OFF 
SET NEWPAGE 0 
SET SPACE 0 
SET PAGESIZE 0 
SET FEEDBACK OFF 
SET HEADING OFF 
SET TRIMSPOOL ON 
SET TERMOUT OFF 
SET VERIFY OFF 
SET TAB OFF 
spool doit.sql 
select 'prompt Enabling row movement in '||table_name||'...'||CHR (10)||'alter table '||table_name||' enable row movement;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Setting initial ext for '||table_name||'...'||CHR (10)||'alter table '||table_name||' move storage (initial 1m);' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Shrinking space for '||table_name||'...'||CHR (10)||'alter table '||table_name||' shrink space;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Rebuilding index '||index_name||'...'||CHR (10)||'alter index '||index_name||' rebuild;' from user_indexes where status = 'UNUSABLE'; 
spool off 
prompt now check and then run @doit.sql 
exit