关于缓慢计数(*)之前的版本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子句对我的情况也无济于事。
答案 0 :(得分:2)
请参阅索引仅扫描wiki条目:
count(*)
much faster now? 特别是,我引用:
重要的是要意识到计划者关心的问题 最小化查询的总成本。随着数据库,成本 I / O通常占主导地位。出于这个原因,“计数(*)没有任何 谓词“查询只会在索引为的情况下使用仅索引扫描 比它的表小得多。这通常只发生在 表的行宽比某些索引宽得多。
另请参阅VACUUM
和ANALYZE
对维护可见性图的讨论。从本质上讲,您可能希望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