2017-07-14 82 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