lat*_*ell 6 postgresql database-design greatest-n-per-group
我有一个带有history
表的 PostgreSQL 数据库,我在其中存储一个fooID
(不是主键序列而是一个文本)、一个属性target
和当前时间戳,每当target
此fooID
更改时:
CREATE TABLE history (
fooId text not null,
target text not null,
updated_at timestamp not null default default now()
);
Run Code Online (Sandbox Code Playgroud)
该表中有几百万个条目,每天有几千次更改。每天我都会扫描表格并保留最后 5 个条目fooId
并删除所有旧条目。
该DELETE ... WHERE id in ... rank() over (partiton by nr order by created_at...
查询是不我的问题,即工程。只是需要很长时间。
我的问题是:标准 PostgreSQL 表是解决此问题的最佳方法吗?
PostgreSQL 表分区在这里有帮助吗?我知道分区用于轻松丢弃超过 X 天的大块数据,但分区按fooId
在我的情况下分区似乎会创建太多分区。
是否有NoSQL数据库会更快,因为它们存储的数据不同?
是否有其他 PostgreSQL 技巧可以帮助我以不同的方式存储数据并针对日常清除的用例进行更优化(SELECT 不是问题,它很少被查询)?
每周 1 小时的独占锁定是可以接受的。大约有 100 万个不同,fooIDs
因此每个fooID
.
小智 3
我能想到的一个选择是在插入新行后立即删除最旧的行。这只需要非常快速的查找,最多限制 6 行,而不是一次遍历所有行。
为了有效地做到这一点,你需要在表上有一个唯一的键:
create table history
(
id serial primary key, -- to make a lookup on a single row efficient
fooid text not null,
target text not null,
updated_at timestamp not null default now()
);
-- to make finding the oldest row for one fooid efficient
create index on history(fooid, updated_at);
Run Code Online (Sandbox Code Playgroud)
然后创建一个触发器,仅保留 a 的最近 5 行fooid
:
create or replace function remove_last()
returns trigger
as
$$
begin
with ranked as (
select id, row_number() over (partition by fooid order by updated_at) as rn
from history
where id <> new.id
and fooid = new.fooid
)
delete from history
where id in (select id
from ranked
where rn >= 5);
return new;
end;
$$
language plpgsql;
create trigger remove_last_trigger
after insert on history
for each row execute procedure remove_last();
Run Code Online (Sandbox Code Playgroud)
在我的笔记本电脑上,一个包含 500 万行(100 万个不同的 fooid 值)的简单测试设置显示触发开销不到一毫秒:
insert into history (fooid, target) values ('1', 'new stuff');
Run Code Online (Sandbox Code Playgroud)
查询计划 -------------------------------------------------- -------------------------------------------------- 插入 stuff.history (成本=0.00..0.01行=1宽度=76)(实际时间=0.062..0.062行=0循环=1) 缓冲区:共享命中=8 ->结果(成本=0.00..0.01行=1宽度=76)(实际时间=0.017..0.017行=1循环=1) 输出:nextval('history_id_seq'::regclass), '1'::text, 'new stuff'::text, now() 缓冲区:共享命中=1 规划时间:0.024 ms 触发器remove_last_trigger:时间=0.438调用=1 执行时间:0.524毫秒
我不知道您的系统中有多少开销以及您是否可以接受,但是“每天进行数千次更改”听起来不像是一个非常繁忙的系统。
归档时间: |
|
查看次数: |
1963 次 |
最近记录: |