首页 > 解决方案 > 在greenplum / postgreSQL中count(*)和count(*)over()性能差异

问题描述

我想查询明细数据和明细数据的总数。一般来说,这需要两句SQL。例如,一个是select col1, col2, col3 from tb limit 50 offset 0,另一个是select count() from tb。为了减少查询次数,我改用“select col1, col2, col3, count() over () totol_count from tb”。

但我发现后者(select col1, col2, col3, count(*) over () totol_count from tb limit 50 offset 0)有时比前者慢得多。为什么?两种方法的性能差异是什么?

这是解释分析。我只是把不同的地方放在上面。

  1. select col1 from tb limit 20 offset 0 Limit (cost=743828.93..747114.71 rows=200 width=287) (actual time=2290.254..2390.969 rows=200 loops=1) -> Gather Motion 20:1 (slice3; segments: 20)(成本=743828.93..747114.71 行=200 宽度=287)(实际时间=2290.248..2390.933 行=200 循环=1)-> 限制(成本=743828.93..747110.71 行=10 宽度=287)(实际时间=2285.350..2385.507 行=200 循环=1)

  2. select count(*) from tb Aggregate (cost=6123212.33..6123212.34 rows=1 width=8) (实际时间=2339.615..2339.616 rows=1 loops=1) -> Gather Motion 20:1 (slice2; segments: 20 )(成本=6123212.10..6123212.32 行=1 宽度=8)(实际时间=635.672..2339.433 行=20 循环=1)-> 聚合(成本=6123212.10..6123212.11 行=1 宽度=8)(实际时间=633.879..633.879 行=1 循环=1)

  3. select col, count(*) over() from tb limit 20 offset 0 Limit (cost=743828.93..747113.21 rows=200 width=287) (实际时间=57787.942..57788.339 rows=200 loops=1) -> WindowAgg ( cost=743828.93..307341631.82 rows=18670608 width=287) (实际时间=57787.936..57788.310 rows=200 loops=1) -> Gather Motion 20:1 (slice3; segments: 20) (cost=743828.93..307014896.18 rows =18670608 宽度=287) (实际时间=1514.368..32796.802 行=18735134 循环=1)

标签: sqlpostgresqlgreenplum

解决方案


只有在看到您的执行计划后,才能确定哪个是您更好的选择。

但是,如果您运行足够的分析,您可以使用:

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'tb'::regclass;

它非常快,但不会给你准确的计数,而是一个近似值。准确性取决于运行分析的频率。

之所以select count(*) from tb慢,与 PostgreSQL 中的 MVCC 实现有关。多个事务可以看到数据的不同状态这一事实意味着“COUNT(*)”没有直接的方法来汇总整个表中的数据;从某种意义上说,PostgreSQL 必须遍历所有行。这通常会导致顺序扫描读取有关表中每一行的信息。 PostgreSQL 中的慢计数


推荐阅读