我正在构建一个网络分析工具并使用Postgresql作为数据库。我不会在每次用户访问时插入postgres,而是每5秒只汇总一次数据:
time country browser num_visits
========================================
0 USA Chrome 12
0 USA IE 7
5 France IE 5
正如您所看到的,每隔5秒钟我会插入多行(每个维度组合一个)。
为了减少需要在查询中扫描的行数,我想根据它们的分辨率有多个具有上述模式的表:5SecondResolution,30SecondResolution,5MinResolution,...,1HourResolution。现在,当用户询问最后一天时,我将转到小时分辨率表,该表小于5秒分辨率表(尽管我也可以使用那个 - 这只是要扫描的行数。)
现在如果小时分辨率表有小时0,1,2,3,......的数据怎么办?但是用户要求从1:59到8:59查看小时趋势。为了获得1:59-2:59期间的数据,我可以对不同的分辨率表进行多次查询,因此我从1MinResolution获得1:59:2:00,从30MinResolution获得2:00-2:30等。 AFAIU我已经将一个查询交换到一个巨大的表(其中有许多相关行要扫描),对中间表进行多次查询+在客户端组合结果。
这听起来像是一个很好的优化吗? 对此有何其他考虑?
答案 0 :(得分:1)
现在如果小时分辨率表有小时0,1,2,3,......的数据怎么办?但是用户要求从1:59到8:59查看小时趋势。为了获得1:59-2:59期间的数据,我可以对不同的分辨率表进行多次查询,因此我从1MinResolution获得1:59:2:00,从30MinResolution获得2:00-2:30等。
如果您希望结果准确,则无法执行此操作。想象一下,如果他们要求从01:30到04:30的一小时决议。你想象的是你从5秒(或1分钟)的res表中获得第一个和最后半个小时,然后是从一个小时表中得到的其余部分。
问题是一小时表被偏移了半个小时,所以答案实际上并不正确;当用户想要2:30到3:30时,每小时将从2:00到3:00等。当你转向更粗略的决议时,这是一个更严重的问题。
所以:这是一种非常合理的优化技术,但前提是您将用户的搜索开始精度限制为聚合表的分辨率。如果他们想要一小时的分辨率,请强制他们选择1:00
,2:00
等,并禁止设置分钟。如果他们想要5分钟的分辨率,请让他们选择1:00,1:05,1:10,......等等。您不必以相同的方式限制结束精度,因为不完整的结束间隔不会影响结束之前的数据,并且在显示时很容易被标记为不完整。 “当前迄今为止”,“到目前为止的小时”等。
如果限制启动精度,不仅可以给出正确的结果,还可以大大简化查询。如果你也限制了 end 精度,那么你的查询纯粹是针对聚合表的,但是如果你想要“更新”数据,就可以很容易地编写类似的内容:
SELECT blah, mytimestamp
FROM mydata_1hour
WHERE mytimestamp BETWEEN current_date + INTERVAL '1' HOUR AND current_date + INTERVAL '4' HOUR
UNION ALL
SELECT sum(blah), current_date + INTERVAL '5' HOUR
FROM mydata_5second
WHERE mytimestamp BETWEEN current_date + INTERVAL '4' HOUR AND current_date + INTERVAL '5' HOUR;
...甚至使用几个级别的联合来满足更粗略分辨率的请求。
答案 1 :(得分:1)
您可以使用继承/分区。一个分辨率主表和许多小时分辨率子表(也许,许多分钟和秒分辨率子表)。
因此,您只需要从主表中进行选择,让每个子表的约束决定哪个是哪个。
当然,你必须添加一个触发器函数来将insert插入到适当的子表中。
插入中的复杂性与显示中的复杂性。