如何使用GROUP BY DATE优化MAX SQL查询

时间:2017-09-27 15:10:08

标签: sql postgresql

我正在尝试从包含3M行的表中优化查询。

列为valuedatetimepoint_id

SELECT DATE(datetime), MAX(value) FROM historical_points WHERE point_id=1 GROUP BY DATE(datetime);

此查询需要2秒钟。

我尝试将point_id=1编入索引,但效果并不好。

是否可以为MAX查询编制索引,或者有更好的方法吗?也许是INNER JOIN?

编辑: 这是类似的解释分析,更好地解决了这个问题。这也是ha性能问题。

EXPLAIN ANALYZE SELECT DATE(datetime), MAX(value), MIN(value) FROM buildings_hispoint WHERE point_id=64 AND datetime BETWEEN '2017-09-01 00:00:00' AND '2017-10-01 00:00:00' GROUP BY DATE(datetime);
>GroupAggregate  (cost=84766.65..92710.99 rows=336803 width=68) (actual time=1461.060..2701.145 rows=21 loops=1)
>  Group Key: (date(datetime))
>  ->  Sort  (cost=84766.65..85700.23 rows=373430 width=14) (actual time=1408.445..1547.929 rows=523621 loops=1)
>        Sort Key: (date(datetime))
>        Sort Method: external sort  Disk: 11944kB
>        ->  Bitmap Heap Scan on buildings_hispoint  (cost=10476.02..43820.81 rows=373430 width=14) (actual time=148.970..731.154 rows=523621 loops=1)
>              Recheck Cond: (point_id = 64)
>              Filter: ((datetime >= '2017-09-01 00:00:00+02'::timestamp with time zone) AND (datetime               Rows Removed by Filter: 35712
>              Heap Blocks: exact=14422
>              ->  Bitmap Index Scan on buildings_measurementdatapoint_ffb10c68  (cost=0.00..10382.67 rows=561898 width=0) (actual time=125.150..125.150 rows=559333 loops=1)
>                    Index Cond: (point_id = 64)
>Planning time: 0.284 ms
>Execution time: 2704.566 ms

2 个答案:

答案 0 :(得分:0)

没有看到EXPLAIN输出很难说出来。我的猜测是你必须在索引定义中加入DATE()调用:

CREATE INDEX historical_points_idx ON historical_points (DATE(datetime), point_id);

此外,如果point_id的值不同于DATE(datetime),那么您必须反转列顺序:

CREATE INDEX historical_points_idx ON historical_points (point_id, DATE(datetime));

请记住,色谱柱的基数对计划者来说非常重要,首选具有高选择性的色谱柱。

答案 1 :(得分:0)

SELECT DISTINCT ON (DATE(datetime)) DATE(datetime), value 
FROM historical_points WHERE point_id=1
ORDER BY DATE(datetime) DESC, value DESC;

将计算出的索引放在DATE(datetime), value上。 [我希望那些不是你真正的专栏名称。使用诸如VALUE之类的保留字作为列名是混淆的一种方法。]

SELECT DISTINCT将像GROUP ON一样工作。 ORDER BY会替换MAX,如果已编入索引,则会很快。

我将这项技术归功于@ErwinBrandstetter。