我们有一张表格,其中包含原始分析(如Google Analytics(分析)和类似的数字),用于查看我们的视频。它包含原始视图,下载,加载等数字。每个视频都由video_id标识。为汇总查询避免外部磁盘排序
数据是每天记录的,但是因为我们需要提取大量指标,所以每天可以包含特定video_id的多个记录。例如:
date | video_id | country | source | downloads | etc...
----------------------------------------------------------------
2014-01-02 | 1 | us | facebook | 10 |
2014-01-02 | 1 | dk | facebook | 13 |
2014-01-02 | 1 | dk | admin | 20 |
我有一个查询,我需要为超过特定日期的新数据的所有视频获取聚合数据。要获得视频ID的我做这个查询:SELECT video_id FROM table WHERE date >= '2014-01-01' GROUP BY photo_id
(或者我可以做一个DISTINCT(video_id)
没有GROUP BY,性能是相同的)。
一旦我有这些ID,我需要总的聚合数据(所有时间)。结合起来,这变成以下查询:
SELECT
video_id,
SUM(downloads),
SUM(loads),
<more SUMs),
FROM
table
WHERE
video_id IN (SELECT video_id FROM table WHERE date >= '2014-01-01' GROUP BY video_id)
GROUP BY
video_id
有约10列我们SUM(5-10取决于查询)。该EXPLAIN ANALYZE
给出如下:
GroupAggregate (cost=2370840.59..2475948.90 rows=42537 width=72) (actual time=153790.362..162668.962 rows=87661 loops=1)
-> Sort (cost=2370840.59..2378295.16 rows=2981826 width=72) (actual time=153790.329..155833.770 rows=3285001 loops=1)
Sort Key: table.video_id
Sort Method: external merge Disk: 263528kB
-> Hash Join (cost=57066.94..1683266.53 rows=2981826 width=72) (actual time=740.210..143814.921 rows=3285001 loops=1)
Hash Cond: (table.video_id = table.video_id)
-> Seq Scan on table (cost=0.00..1550549.52 rows=5963652 width=72) (actual time=1.768..47613.953 rows=5963652 loops=1)
-> Hash (cost=56924.17..56924.17 rows=11422 width=8) (actual time=734.881..734.881 rows=87661 loops=1)
Buckets: 2048 Batches: 4 (originally 1) Memory Usage: 1025kB
-> HashAggregate (cost=56695.73..56809.95 rows=11422 width=8) (actual time=693.769..715.665 rows=87661 loops=1)
-> Index Only Scan using table_recent_ids on table (cost=0.00..52692.41 rows=1601328 width=8) (actual time=1.279..314.249 rows=1614339 loops=1)
Index Cond: (date >= '2014-01-01'::date)
Heap Fetches: 0
Total runtime: 162693.367 ms
正如你所看到的,它的使用(相当大的)外部磁盘合并排序并采取了很长一段时间。我不确定为什么这些排序是首先触发的,我正在寻找一种方法来避免它,或者至少将其最小化。我知道增加work_mem
可以缓解外部磁盘合并,但在这种情况下,它似乎过度并且work_mem超过500MB似乎是个不好的主意。
该表有两个(相关)索引:一个在video_id
上,另一个在(date, video_id)
上。
编辑:运行后更新查询ANALYZE table
。
您的执行计划与您的示例查询不匹配。你有一个合并连接,我无法匹配你向我们显示的SQL。你确定你向我们展示了一切吗? – 2014-10-20 15:17:13
它完全匹配,只有我有变化的是一些名称。我怀疑合并连接是一种优化,其中内部查询被视为JOIN而不是值列表。 – 2014-10-20 15:18:14
连接可能来自postgres将子查询转换为连接。 – 2014-10-20 15:18:42