如何解决通过两个时间戳从多个表中获取数据
PostgreSQL 10.12
我有一张表格,其中包含按日期和小时分组的计算数据,例如:
hourly_stats
clicks_count | visitors_count | product_id | promoter_id | bundle_id | date_time
------------------------------------------------------------------------------------------
15 | 6 | 123 | 456 | 789 | 2018-11-02 12:00:00
8 | 3 | 123 | 456 | 789 | 2018-11-02 16:00:00
2 | 1 | 123 | 456 | 789 | 2018-11-13 10:00:00
5 | 2 | 123 | 456 | 789 | 2018-11-13 21:00:00
每隔一个小时,我都会收集前一个小时的统计信息并将其插入表格中。
此外,为了始终显示最新数据,我使用实例化视图,该视图存储从当前小时的开始到当前时刻(每5分钟刷新一次)的计算数据。
查询的核心部分始终基于两个时间戳值,如下所示:
SELECT *
FROM (
SELECT
clicks_count,visitors_count,product_id,promoter_id,bundle_id,date_time
FROM hourly_stats
UNION ALL (
SELECT
clicks_count,date_time
FROM materialized_stats
)
)
WHERE (date_time > start_date AND date_time <= end_date)
此核心部分用于多个非常复杂的查询,这些查询太慢。例如,如果表在其中一种情况下具有超过2000万条记录,则需要花费超过1.5分钟才能完成查询(如果没有行用start_date
和end_date
进行过滤)。
我决定再添加两个表,其中包含按年-月-日分组的计算数据:
daily_stats
clicks_count | visitors_count | product_id | promoter_id | bundle_id | date_time
------------------------------------------------------------------------------------------
23 | 9 | 123 | 456 | 789 | 2018-11-02
7 | 3 | 123 | 456 | 789 | 2018-11-13
以及按年份-月份:
monthly_stats
clicks_count | visitors_count | product_id | promoter_id | bundle_id | date_time
------------------------------------------------------------------------------------------
30 | 12 | 123 | 456 | 789 | 2018-11
因此,如果我有start_date = '2019-01-01 00:00:00'
和end_date = '2020-08-12 16:00:00'
,我将能够收集这样的数据
(SELECT
clicks_count,date_time
FROM monthly_stats
WHERE 'monthly_condition')
UNION ALL
(SELECT
clicks_count,date_time
FROM daily_stats
WHERE 'daily_condition')
UNION ALL
(SELECT
clicks_count,date_time
FROM hourly_stats
WHERE 'hourly_condition')
UNION ALL (
SELECT
clicks_count,date_time
FROM materialized_stats
)
每个计算行仅在基本时间段(月,日或小时)结束后才添加到相应的表中。因此,对于特定的product_id | promoter_id | bundle_id
集,我应该得到:
-
来自
- 19行
来自
daily_stats
+ 的 - 11行
来自
hourly_stats
+ 的 - 16行
-
materialized_stats
中的1行
monthly_stats
+ 的(在应用程序层上)已经实施的限制:
- max
end_date
的值可能等于当天的结束时间 -
start_date
始终小于end_date
-
start_date
和end_date
的值以小时为单位指定
问题:如何在上面实现这些“ monthly_condition”,“ daily_condition”和“ hourly_condition”?它们应该基于start_date
和end_date
部分,但是我完全不知道该怎么做。
感谢您的帮助。
解决方法
这是一个有趣的问题。对于SQL Server,我不得不解决一次。 PostgreSQL使它变得更加容易。到fullness
cte为止的所有内容均已测试。由于我没有您的表格或数据,因此allstats
cte是最好的猜测。
with invars as (
select '2016-08-15 12:35:00'::timestamptz as start_date,'2020-08-12 19:00:00'::timestamptz as end_date
),days as (
select c.dhour,tstzrange(
date_trunc('hour',i.start_date),date_trunc('hour',i.end_date),'[)') as qrange
from invars i
cross join lateral generate_series(
date_trunc('hour',interval '1 hour'
) as c(dhour)
),calendar as (
select dhour,date_trunc('day',dhour) as dday,date_trunc('month',dhour) as dmonth,qrange
from days
),fullness as (
select dhour,dday,dmonth,qrange,qrange @> tstzrange(dday,dday + interval '1 day','[)') as full_day,qrange @> tstzrange(dmonth,dmonth + interval '1 month','[)') as full_month
from calendar
),allstats as (
select clicks_count,visitors_count,product_id,promoter_id,bundle_id
from monthly_stats
where date_time in (select distinct to_char(dmonth,'YYYY-MM')
from fullness where full_month)
union all
select clicks_count,bundle_id
from daily_stats
where date_time in (select distinct to_char(dday,'YYYY-MM-DD')
from fullness where full_day and not full_month)
union all
select clicks_count,bundle_id
from hourly_stats
where date_time in (select dhour from fullness
where not full_day and not full_month
and dhour < date_trunc(hour,now()))
union all
select clicks_count,bundle_id
from materialized_stats
)
select * from allstats;
我认为您的问题描述遗漏了start_date
可以在一个月甚至一天的中间开始的事实。该查询涵盖了这一点。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。