有效地计算当前活动用户的数量

时间:2014-12-28 22:37:50

标签: sql performance postgresql indexing postgresql-performance

我目前只是想弄清楚如何在应用上的任何给定“页面”上有效地计算活跃用户的数量。我正在使用PostgreSQL并有一个这样的表:

CREATE TABLE user_is_viewing_page (
  user_id BIGINT,
  page_id BIGINT,
  timestamp TIMESTAMP
);

每个用户使用他们正在查看的页面的ID每隔10秒左右发送到一个服务器,并且将在数据库中插入一个新行。

当前查询我必须计算任何给定页面上“活动”用户的数量:

SELECT COUNT(DISTINCT user_id)
FROM user_is_viewing_page WHERE page_id = 1 
                          AND timestamp > CURRENT_TIMESTAMP - INTERVAL '10 seconds';

我想知道使用此查询的最有效方法是什么。请记住,我需要经常访问此计数(每页每5-10秒)。

  • 我应该使用查询创建物化视图吗? (知道我必须经常访问它)
  • 我是否应该在每次需要时自行运行查询?
  • 将表格编入索引以便快速查找的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

物化视图无济于事,因为您的查询需要基于最新数据,您必须像查询一样频繁刷新MV。

基于触发器的解决方案将是另一种选择:使辅助表保持最新,每页当前计数。但是我希望(你的很多)写操作的额外成本 高于读取操作的增益。所以我也会这样做。

当您使用一张大桌子时,我建议使用partial index

CREATE INDEX foo ON user_is_viewing_page (page_id, timestamp)
WHERE timestamp > '2014-12-29 23:30:00'::timestamp;  -- start with 'now'

查询(主要是你已经拥有的):

SELECT COUNT(DISTINCT user_id)
FROM   user_is_viewing_page
WHERE  page_id = 1 
AND    timestamp > LOCALTIMESTAMP - INTERVAL '10 sec';

CURRENT_TIMESTAMP也可以。但LOCALTIMESTAMP对您的设置更有意义。 Per documentation:

  

CURRENT_TIMECURRENT_TIMESTAMP按时区提供值;   LOCALTIMELOCALTIMESTAMP提供没有时区的值。

部分索引本身的查找与使用完整索引的成本基本相同。但是因为你的表应该是 big ,所以部分索引应该 小于完整索引,这将非常适合并保持在RAM中并且通常更快。如果您有足够的RAM,请将性能与没有WHERE条件的简单,大的完整索引进行比较。

部分指数的优势明显随着时间的推移而恶化。以您选择的时间间隔创建一个在WHERE条件中具有更新时间戳的新索引,然后删除旧索引。查询将立即启动新的(较小的)索引,因此可以轻松删除旧索引。这些相关答案中概述了可能的自动化方法,并提供了更多解释:

您可能需要在查询中添加索引的确切WHERE条件(虽然看似多余),以说服查询计划员使用部分索引是安全的。特别是使用预处理语句(包括plpgsql函数中的所有语句),其中要比较的实际时间戳是参数化的,否则Postgres不能使用generic query plan的部分索引。

在上面的示例中,您将WHERE条件添加到查询中:

AND timestamp > '2014-12-29 23:30:00'::timestamp -- matches index condition exactly

更为通用的解决方案可以在the linked answer above中找到。

除此之外:我不会使用" timestamp"作为标识符,因为它是基本类型名称。