2017-07-14 113 views
1

我與camera_activities名稱的表,有超過百萬的在記錄越多,表結構就像刪除數百萬的記錄

CREATE TABLE camera_activities 
(
    id serial NOT NULL, 
    camera_id integer NOT NULL, 
    access_token_id integer, 
    action text NOT NULL, 
    done_at timestamp with time zone NOT NULL, 
    ip inet, 
    extra json, 
    camera_exid text, 
    name text 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE camera_activities 
    OWNER TO 8hhjhjgghg7; 

-- Index: camera_activities_camera_id_done_at_index 

-- DROP INDEX camera_activities_camera_id_done_at_index; 

CREATE UNIQUE INDEX camera_activities_camera_id_done_at_index 
    ON camera_activities 
    USING btree 
    (camera_id, done_at); 

和一個記錄是像

record

這是問題所在,

我希望在2016年前將刪除所有記錄,他們將會是如此之多,範圍是在2014年之間等等,我們開始在2014年添加數據..

我試過了一個簡單的查詢,它的效果很好,例如,如果我刪除2個日期作爲

delete from camera_activities where done_at>'2017-07-12 10:55:37+00' and done_at<='2017-07-13 09:23:00+00 

這工作,但它的很多費時,有超過百萬的記錄,有沒有快速的方法來完成這項工作?

注意:如果我可能會將日期範圍增加到一個月或超過一個月,則查詢會繼續運行,並且不會返回任何結果。

任何幫助或指導將有所幫助,

+0

關於您想要保存多少個值?所以我想大約在2016年之後有多少價值? – yanman1234

+0

您可以創建新表,從現有表中複製所需的所有內容,然後刪除舊錶。 – fen1x

+1

我正在建議fen1x說什麼,你會'截斷'比'delete'快得多的舊錶,但這隻有在數據少於刪除時纔有意義。 – yanman1234

回答

2

執行大量DELETE操作有兩種基本方法。

1)最終創建一個表,刪除舊,並重新命名新的,ANALYZE新表:

begin; 
create table camera_activities_new (like camera_activities including all); 

insert into camera_activities_new 
select * from camera_activities 
where done_at >= ''2016-01-01'::date; 

alter sequence camera_activities_id_seq owned by camera_activities_new; 
drop table camera_activities; 
alter table camera_activities_new rename to camera_activities; 
alter index camera_activities_new_camera_id_done_at_idx rename to camera_activities_camera_id_done_at_idx; 
commit; 

analyze camera_activities; 

這種做法保證了結果表將在最佳狀態(無腹脹)。但它可能不太方便,你的系統負載很重,並且涉及到桌子。在這種情況下,「順利刪除」看起來可能會更好。 2)「平滑」刪除:每次只刪除相對少量的行,使用更積極的自動清理設置和控制膨脹。

例子,說明如何刪除拆分到多個獨立的交易(在bash;依靠$PGDATABASE$PGHOST$PGUSER$PGPASSWORD環境變量):

while true; do 
    res=$(psql -c "delete from camera_activities where id in (select id camera_activities where done_at < '2016-01-01'::date limit 500);" \ 
    | grep DELETE | awk {'print $2'}) 
    if [[ $res = '0' ]]; then break; fi; 
    sleep 0.3; # control speed here; check bloating level 
done 

- 這會自動停止時沒有行被留下來刪除。

您在(camera_id, done_at)上的索引應加速子查詢,使位圖索引掃描 - 檢查EXPLAIN。但也許這是值得對done_at一個單獨的索引,也可以是btreebrin在此情況下(大小有損,但小):

create i_camera_activities_done_at on camera_activities using brin(done_at); 

的「更積極」(而不是默認設置)的自動清理設置,例如:

log_autovacuum_min_duration = 0 
autovacuum_vacuum_scale_factor = 0.01 
autovacuum_analyze_scale_factor = 0.05 
autovacuum_naptime = 60 
autovacuum_vacuum_cost_delay = 20 

不同的查詢,這有助於你看看錶的腹脹級別:

+0

這是多麼輝煌的答案。 –

+0

嗨,我剛剛得到了一個錯誤 '錯誤:不能刪除表camera_activities,因爲其他對象依賴於它 細節:默認爲表camera_activities_new列ID取決於序列camera_activities_id_seq 提示:使用DROP ... CASCADE刪除依賴對象也是如此。' –

+0

'在camera_activities_new擁有的序列camera_activities_id_seq''在'drop ...'之前''。對不起,忘了序列。 – Nick