PostgreSQL:DISTINCT ON中的最新行比GROUP BY中的最大行性能低

问题描述 投票:2回答:1

我有一种情况,我想更好地理解:

我有一个表t有两行和一个索引:

CREATE TABLE t (
  refid                 BIGINT NOT NULL,
  created               TIMESTAMPTZ NOT NULL
);
CREATE INDEX t_refid_created ON t (refid, created);

为了获得每个不同的created的最新(具有最高的refid值)行,我编写了两个查询:

-- index only scan t_refid_created_desc_idx
SELECT DISTINCT ON (refid) * FROM t
ORDER BY refid, created DESC;

-- index scan t_refid_created_idx 
SELECT refid, max(created) FROM t GROUP BY refid;

t具有大约16M行并且refid中的方差是大约500个不同的值时,第二个查询的返回速度明显快于第二个查询。

起初我认为,因为我按created DESC排序,它需要进行向后索引扫描,并从具有高方差(创建)的值开始。所以我添加了以下索引:

CREATE index t_refid_created_desc_idx ON t (refid, created DESC);

它确实被使用(而不是对先前索引的向后扫描),但没有任何改进。

如果我理解正确,第二个查询将通过refid聚合,然后扫描每个聚合以找到最大created值。这听起来像是很多工作。根据我的理解,第一个查询应该简单地迭代索引的第一部分,然后对于每个refid它应该使用索引的第二部分,取第一个值。

显然事实并非如此,SELECT DISTINCT查询的时间是GROUP BY的两倍。

我在这里错过了什么?

以下是第一次和第二次查询的EXPLAIN ANALYZE输出:

Unique  (cost=0.56..850119.78 rows=291 width=16) (actual time=0.103..13414.913 rows=469 loops=1)
  ->  Index Only Scan using t_refid_created_desc_idx on t  (cost=0.56..808518.47 rows=16640527 width=16) (actual time=0.102..12113.454 rows=16640527 loops=1)
        Heap Fetches: 16640527
Planning time: 0.157 ms
Execution time: 13415.047 ms
Finalize GroupAggregate  (cost=599925.13..599932.41 rows=291 width=16) (actual time=3454.350..3454.884 rows=469 loops=1)
  Group Key: refid
  ->  Sort  (cost=599925.13..599926.59 rows=582 width=16) (actual time=3454.344..3454.509 rows=1372 loops=1)
        Sort Key: refid
        Sort Method: quicksort  Memory: 113kB
        ->  Gather  (cost=599837.29..599898.40 rows=582 width=16) (actual time=3453.194..3560.602 rows=1372 loops=1)
              Workers Planned: 2
              Workers Launched: 2
              ->  Partial HashAggregate  (cost=598837.29..598840.20 rows=291 width=16) (actual time=3448.225..3448.357 rows=457 loops=3)
                    Group Key: refid
                    ->  Parallel Seq Scan on t  (cost=0.00..564169.53 rows=6933553 width=16) (actual time=0.047..2164.459 rows=5546842 loops=3)
Planning time: 0.157 ms
Execution time: 3561.727 ms

第一个查询在大约10秒内运行,而第二个查询在2秒内完成相同的结果!甚至没有使用索引!

我正在使用PostgreSQL 10.5。

postgresql group-by postgresql-10 distinct-on
1个回答
1
投票

我无法回答谜语为什么DISTINCT ON不考虑第二个计划。根据成本估算,我们看到PostgreSQL认为它更便宜。

我想没有人实施将DISTINCT推向并行计划。你可以问邮件列表。

但是,第一个查询的问题是1600万个堆提取。这意味着这实际上是一个正常的索引扫描!对于策划者来说,这似乎是一个糟糕的错误。

如果我是对的,桌面上用于清理可见性图的VACUUM应该会大大改善第一个查询。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.