我目前正在开发一个项目,涉及跟踪用户及其对我的数据库的操作(PostgreSQL作为RDMS),并且在尝试对每个用户的出现执行COUNT(*)时遇到了问题。我想要的是能够有效地计算每个用户从每个记录中出现的次数,并且能够实现查看特定<的计数< strong>日期范围。
所以,问题是我们如何计算用户从表格内容中出现的总次数,以及我们如何计算日期范围内的总数。
我尝试了什么
正如您所知,Postgres使用索引不能很好地支持COUNT(*),因此我们必须考虑其他方法来减少它所查看的记录数,以加快查询速度。所以我的第一种方法是创建一个表来跟踪用户与其关联的日志消息的次数,以及在哪一天(类似于物化视图背后的想法,但我不想继续刷新物化视图用我的计数查询)。以下是我的想法:
CREATE TABLE users_counts(user varchar(65536), counter int default 0, day date);
CREATE RULE inc_user_date_count
AS ON INSERT TO main_table
DO ALSO UPDATE users_counts SET counter = counter + 1
WHERE user = NEW.user AND day = DATE(NEW.date_);
这样做的每次将新记录插入到我的'main_table'中时,我们更新当前的users_counts表以增加日期等于新记录日期的记录,并且用户名相同。
注意:'main_table'中的date_列是一个时间戳,所以我必须将新记录date_强制转换为DATE类型。
问题是,如果当前日期我的新表'users_count'中的用户列值尚未存在,那么什么都不会更新。
这是我的问题:
我如何编写规则,以便检查当前用户是否存在,如果是,则增加该计数器,否则使用user,day和counter of 1插入新行; < / p>
我也想知道我的方法是否有意义,或者是否有任何我想念的想法,我只是没想过。随着我的数据库的增长,执行计数的效率越来越低,所以我想避免任何性能瓶颈。
编辑1:我能够通过创建单独的RULE来实现这一点,但我不确定这是否正确:
CREATE RULE test_insert AS ON INSERT TO main_table
DO ALSO INSERT INTO users_counts(user, counter, day)
SELECT NEW.user, 1, DATE(NEW.date)
WHERE NOT EXISTS (SELECT user FROM users.log_messages WHERE user = NEW.user_);
基本上,如果用户在我的CACHED表中已经存在,名为user_counts,并且上面的第一条规则更新了计数,则会发生插入。
我不确定的是我如何知道何时首先调用哪个规则,更新规则或插入..并且必须有更好的方法,如何组合这两个规则?可以用函数完成吗?
答案 0 :(得分:1)
对于count(*)查询,postgresql确实很慢。但是,如果您确实有一个where子句来限制条目数,则查询将更快。如果您正在使用postgresql 9.2或更新版本,那么这个查询将和它在mysql中一样快,因为9.2中添加了仅索引扫描,但最好解释一下您的查询以确保它。
我的解决方案有意义吗?
非常如此,只要您的解释分析显示仅使用索引扫描。基于触发器的解决方案(如您已调整的解决方案)可广泛使用。但是你已经意识到初始状态的问题出现了(无论是更新还是插入)。
首先调用哪条规则
来自http://www.postgresql.org/docs/9.1/static/sql-createrule.html的应用了同一个表和相同事件类型的多个规则 按字母顺序排列。
这同样适用于触发器。如果您想要执行特定规则,请先更改其名称,使其按字母顺序排列更高。
如何合并这两条规则?
一种解决方案是修改规则以执行upsert(在该页面的底部查看样本upsert)。另一种是用初始值填充计数器表。诀窍是同时创建触发器以避免错误。这blog post解释得非常好。
虽然初始设置会很慢,但每个插件的速度可能会更快。两个相反的因素是WHERE NOT EXISTS查询的缓慢与捕获异常的开销。
提示:包含EXCEPTION子句的块明显更多 进入和退出比没有一个的块贵。所以,不要 不需要使用EXCEPTION。
获取上面链接的postgresql文档页面。