我目前只是想弄清楚如何在应用上的任何给定“页面”上有效地计算活跃用户的数量。我正在使用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秒)。
答案 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_TIME
和CURRENT_TIMESTAMP
按时区提供值;LOCALTIME
和LOCALTIMESTAMP
提供没有时区的值。
部分索引本身的查找与使用完整索引的成本基本相同。但是因为你的表应该是 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"作为标识符,因为它是基本类型名称。