postgresql 9.2上的慢计数(*)

时间:2012-12-13 07:50:22

标签: postgresql postgresql-9.2

关于缓慢计数(*)之前的版本9.2,这里和那里(包括关于postgres web的官方帖子)有一些讨论;不知怎的,我没有找到满意的答案。

基本上我安装了postgres 9.1,我观察到慢计数(*)就像

一样简单
select count(*) from restaurants;

在记录为100k +的表上。平均请求大约是 850ms 。好吧,我认为这是人们一直在谈论的postgres 9.1及以下的缓慢计数的症状,因为postgres 9.2有一些新功能,如仅索引扫描。我想通过使用9.1中的相同数据集进行实验,并将其放在9.2上。我调用count语句,它仍然会给出一个不好的结果,如9.1。

explain analyze select count(*) from restaurants;
------------------------------------------------------------------
Aggregate  (cost=23510.35..23510.36 rows=1 width=0) (actual time=979.960..979.961 rows=1 loops=1)
   ->  Seq Scan on restaurants  (cost=0.00..23214.88 rows=118188 width=0) (actual time=0.050..845.097 rows=118188 loops=1)
 Total runtime: 980.037 ms

有人能建议解决这个问题吗?我是否需要在postgres上配置任何内容才能启用该功能?

P.S。 where子句对我的情况也无济于事。

2 个答案:

答案 0 :(得分:2)

请参阅索引仅扫描wiki条目:

特别是,我引用:

  

重要的是要意识到计划者关心的问题   最小化查询的总成本。随着数据库,成本   I / O通常占主导地位。出于这个原因,“计数(*)没有任何   谓词“查询只会在索引为的情况下使用仅索引扫描   比它的表小得多。这通常只发生在   表的行宽比某些索引宽得多。

另请参阅VACUUMANALYZE对维护可见性图的讨论。从本质上讲,您可能希望VACUUM更具攻击性,并且您希望在首次加载后手动VACUUM ANALYZE

答案 1 :(得分:0)

这是由于PostgreSQL的MVCC实现。简而言之,为了计算表行,PostgreSQL需要确保它们存在。但考虑到每条记录的多个快照/版本,PostgreSQL无法直接汇总整个表。因此,PostgreSQL会读取每一行,执行顺序扫描。!

如何解决这个问题?

有多种方法可以解决此问题,包括a trigger-based mechanism。如果您可以使用估计的行数,可以检查PostgreSQL pg_class reltuples:

    SELECT reltuples::BIGINT AS estimate FROM pg_class WHERE relname=<table_name>

<强> Reltuples:

  

[这是]表中的行数。这只是计划者使用的估计值。 - PostgreSQL: Documentation: pg_class

更多信息:

https://medium.com/@vinicius_edipo/handling-slow-counting-with-elixir-postgresql-f5ff47f3d5b9

http://www.varlena.com/GeneralBits/120.php

https://www.postgresql.org/docs/current/static/catalog-pg-class.html