SQL聚合加入和子查询优化

时间:2017-05-02 08:08:50

标签: sql postgresql

我试图通过两个关系(购买和使用)的时间段来获取聚合值并加入它们,以便我可以在一个报告中获得结果并且还可以绘制它们的比率。我正在使用PostgreSQL。最终报告要求是:dateTime, u.sum, b.sum, b.sum/u.sum

以下查询有效,但对于较大的表格大小,其扩展性很差。

SELECT b2.datetime AS dateTime, b2.sum AS BUY_VOLUME, u1.sum AS USE_VOLUME, 
CASE u1.sum
   WHEN 0 THEN 0
   ELSE (b2.sum / u1.sum)
END AS buyToUseRatio
    FROM(
    SELECT SUM(b.total / 100.0) AS sum, date_trunc('week', (b.datetime + INTERVAL '1 day')) - INTERVAL '1 day' as datetime
    FROM buys AS b
    WHERE 
    datetime > date_trunc('month', CURRENT_DATE) - INTERVAL '1 year'
    GROUP BY datetime) AS b2
INNER JOIN (SELECT SUM(u.amount) / 100.00 AS sum, date_trunc('week', (u.datetime + INTERVAL '1 day')) - INTERVAL '1 day' AS datetime
FROM uses AS u
WHERE 
 datetime > date_trunc('month', CURRENT_DATE) - INTERVAL '1 year'
GROUP BY datetime) AS u1 ON b2.datetime = u1.datetime
ORDER BY b2.datetime ASC;

我想知道是否有人可以通过提供一个可以获得最终结果并且执行速度更快的替代查询来帮助我。

我感谢任何帮助:-)我的初级SQL有点生疏,我想不出另一种方法这样做而不创建索引。提前谢谢。

2 个答案:

答案 0 :(得分:0)

所以答案取决于你的桌子有多大,但如果是我,我会创建一两个新的"摘要"基于您的查询的表并确保更新它们(每天运行一次批处理作业以更新它们,或者每小时运行一次,其中包含最近更改的所有数据)。

然后,我将能够更快地查询这些表格。

但是,如果您的表格非常小​​,那么只需按照您的方式继续操作并使用索引,直到您获得可接受的时间。

答案 1 :(得分:0)

至少,这些索引可以帮助您进行查询:

create index idx_buys_datetime on buys(datetime);
create index idx_uses_datetime on uses(datetime);

您的查询似乎很好。但是,您可以使用full join(而不是inner)来获取所有行,其中至少您的一个表中包含数据。您甚至可以使用generate_series()始终拥有1年的结果,即使您的任何一个表中都没有数据,但我不确定这是否是您需要的。此外,还可以更轻松地编写其他一些内容;您的查询可能如下所示:

select    dt, buy_volume, use_volume, buy_volume / nullif(use_volume, 0.0) buy_to_use_ratio
from      (select   sum(total / 100.0)  buy_volume, date_trunc('week', (datetime + interval '1 day')) - interval '1 day' dt
           from     buys
           where    datetime > date_trunc('month', current_timestamp - interval '1 year')
           group by 2) b
full join (select   sum(amount) / 100.0 use_volume, date_trunc('week', (datetime + interval '1 day')) - interval '1 day' dt
           from     uses
           where    datetime > date_trunc('month', current_timestamp - interval '1 year')
           group by 2) u using (dt)
order by  1

http://rextester.com/YVASV92568