我正在重新实施一个应用程序来支持国家工程竞赛,将其从本地服务器迁移到云端。
为了告诉团队目前他们的立场,查询的格式为
select 1 + count(*) from team where where score < ?
团队成绩非常动态变化。最多可能有200万个团队,我需要每秒处理至少10个这样的查询。
原始版本通过使用单独的Berkeley DB团队/分数记录获得所需的性能(实际上它已经与1999硬件一起使用)。 Berkeley DB中有一个“记录号”功能,它提供了完全正确的功能,而且速度非常快。
Heroku显然无法支持Berkeley DB。 PostgreSQL,它们的标准数据库,使用完整的表或索引扫描执行select count(*)
,这太慢了。
有关如何进行的任何想法?我不是和Heroku结合,而是必须转向某种云解决方案。
答案 0 :(得分:2)
创建排名表并尽可能频繁地更新。包括类别(开放或官方)和分数,这样您就不必在查询时将其加入团队表:
create table "rank" (
team integer primary key,
category integer,
score integer,
rank_consolidated integer,
rank_category integer
);
begin;
truncate table "rank"
;
insert into "rank" (team, category, score, rank_consolidated, rank_category)
select
team, category, score,
rank() over(order by score desc) rank_consolidated,
rank() over(partition by category order by score desc) rank_category
from team
;
commit
;
select * from "rank" where team = 11;
的确切排名行为
答案 1 :(得分:2)
答案 2 :(得分:0)
在分数上设置索引应该避免全表扫描。
答案 3 :(得分:0)
如果读取的内容比它写的要多得多,并且它总是必须是最新的,那么这是触发器维护的摘要表(一种物化视图)的理想工作。
在team
表上有一个触发器,AFTER EACH INSERT OR UPDATE OR DELETE FOR EACH ROW
执行触发器功能,使用新分数更新该团队的team_summary
表条目。
team_summary
表可以通过简单的直接索引查找来获取,因此它会很快疯狂。由于Pg支持同时读者和编写者,team_summary
表将保持响应,即使它经常更新。为了获得最佳效果,您真正需要做的唯一事情是将FILLFACTOR
设置为team_summary
表中的50,以便HOT可以很好地工作,并确保autovacuum设置为经常运行以传播负载真空I / O流失。
编写触发器应该非常简单。您必须小心编写并发安全触发器,当您通过多个并发连接同时更新同一团队时,该触发器不会中断。类似的东西:
UPDATE team_summary SET score = score + 1 WHERE team_id = NEW.team_id;
在SERIALIZABLE
和READ COMMITTED
隔离下,应该没问题。见Concurrency control。唯一困难的是,在将新团队的第一行插入team_summary
之前,您必须确保在team
中插入一个新行,这样您的触发器就不必处理令人惊讶的棘手案例。 team_summary
表中可能尚不存在team
行。获得upup / merge是正确的。
如果写入速率也非常高,并且您只能每隔几秒钟或几分钟更新一次结果,请使用Clodoaldo的方法。