我在自己的机器上使用PostgreSQL 9.6.1来存储此数据库。
我有这个交易数据库。整个数据库大约有1亿行x 30列。交易跨越了过去四年。
对于此查询,有三个相关列:
我有兴趣返回四列的输出,如下图所示(对不起链接 - 还没有足够的代表来嵌入图片:
输出是特定时间戳期间的交易计数,过去60分钟内唯一活跃供应商的数量,以及过去60分钟内的每小时收入。
以下是我用来尝试实现此目的的代码。
SELECT transaction_timestamp,
COUNT(transaction_timestamp) AS "transaction_timestamp",
(SELECT COUNT(DISTINCT vendor_id)
FROM transactions_db
WHERE transaction_timestamp BETWEEN t.transaction_timestamp - INTERVAL '60 MINUTES' AND t.transaction_timestamp
) AS "lag_60_transaction_count",
(SELECT SUM(revenue) / COUNT(DISTINCT vendor_id)
FROM transactions_db
WHERE transaction_timestamp BETWEEN t.transaction_timestamp - INTERVAL '60 MINUTES' AND t.transaction_timestamp
) AS "rolling_hourly_rate"
FROM transactions_db t
GROUP BY transaction_timestamp
ORDER BY transaction_timestamp;
这是EXPLAIN输出:
GroupAggregate (cost=21989857.85..681893649752.90 rows=108423 width=56)
Group Key: t.transaction_timestamp
-> Sort (cost=21989857.85..22252785.49 rows=105171056 width=8)
Sort Key: t.transaction_timestamp
-> Index Only Scan using timestamp_vendor_revenue_idx on transactions_db t (cost=0.57..3663118.41 rows=105171056 width=8)
SubPlan 1
-> Aggregate (cost=3143836.32..3143836.33 rows=1 width=8)
-> Index Only Scan using timestamp_vendor_revenue_idx on transactions_db (cost=0.57..3142521.68 rows=525855 width=4)
Index Cond: ((transaction_timestamp >= (t.transaction_timestamp - '01:00:00'::interval)) AND (transaction_timestamp <= t.transaction_timestamp))
SubPlan 2
-> Aggregate (cost=3145150.96..3145150.97 rows=1 width=32)
-> Index Only Scan using timestamp_vendor_revenue_idx on transactions_db transactions_db_1 (cost=0.57..3142521.68 rows=525855 width=10)
Index Cond: ((transaction_timestamp >= (t.transaction_timestamp - '01:00:00'::interval)) AND (transaction_timestamp <= t.transaction_timestamp))
话虽这么说,这个查询花了不可思议的长时间运行(8个多小时 - 一夜之间运行,今天早上仍在运行)。
我在transaction_timestamp,vendor_id和收入上创建了一个复合索引,但运行时间仍然非常高。
当我对数据子集运行此查询时(我有一个包含一天数据的示例表),查询将在2.1秒后返回。
我对于优化数据库和查询几乎完全是绿色的,所以我可以在2.1秒内在一天的数据中返回此查询这一事实让我相信我可以做些什么来使这个查询在主数据库的合理时间。
如果我遗漏了任何其他信息,请告诉我。
示例数据,查询和输出:http://rextester.com/AOKNT5900
答案 0 :(得分:0)
尝试这样的事情:
select t1.transaction_timestamp
, count (t1.*) transactions
, count(distinct t1.vendor_id) vendors
, sum(t1.revenue) / count(distinct t1.vendor_id) hourly_rate
from transactions_db t1 join transactions_db t2
on t1.transaction_timestamp > t2.transaction_timestamp
and t1.transaction_timestamp < t2.transaction_timestamp + INTERVAL '61 MINUTES'
group by t1.transaction_timestamp
另外,除非您确实需要整个数据库,否则请对transaction_timestamp和/或vendor_id进行过滤
答案 1 :(得分:0)
此版本提供与当前查询相同的结果。我必须将计算分成两部分,然后在最后加入。检查两个解释并让我知道。
第二个查询中的关键是创建一个子查询,将每个时间戳作为一个组,然后加入以获得该组中的每个收入。
FROM ( SELECT DISTINCT transaction_timestamp
FROM transactions_db) t1
<强> DEMO 强>
WITH transaction_total as (
SELECT transaction_timestamp,
COUNT (transaction_timestamp) AS "total"
FROM transactions_db t
GROUP BY transaction_timestamp
), lag_60 as (
SELECT t1.transaction_timestamp,
COUNT(DISTINCT t2.vendor_id) as lag_60_transaction_count,
SUM(revenue) / COUNT(DISTINCT t2.vendor_id) AS "rolling_hourly_rate"
FROM ( SELECT DISTINCT transaction_timestamp
FROM transactions_db) t1
join transactions_db t2
on t1.transaction_timestamp <= t2.transaction_timestamp + INTERVAL '60 MINUTES'
and t1.transaction_timestamp >= t2.transaction_timestamp
GROUP BY t1.transaction_timestamp
)
SELECT T1.transaction_timestamp,
T1.total,
T2.lag_60_transaction_count,
T2.rolling_hourly_rate
FROM transaction_total T1
JOIN lag_60 T2
USING (transaction_timestamp)
ORDER BY T1.transaction_timestamp;
;
<强>输出:强>