快速发现PostgreSQL中表的行数

Ren*_*ani 89 sql postgresql row count

我需要知道表中的行数来计算百分比.如果总计数大于某个预定义常量,我将使用常量值.否则,我将使用实际的行数.

我可以用SELECT count(*) FROM table.但是如果我的常量值是500,000并且我的表中有5,000,000,000行,那么计算所有行会浪费很多时间.

一旦超过常数值,是否可以停止计数?

只要它低于给定的限制,我只需要确切的行数.否则,如果计数高于限制,我会使用限制值,并希望尽快得到答案.

像这样的东西:

SELECT text,count(*), percentual_calculus()  
FROM token  
GROUP BY text  
ORDER BY count DESC;
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 191

在PostgreSQL中,已知表中的行计数速度很慢.为了获得精确的数字,由于MVCC的性质,它必须完整地计算行数.有一种方法来大大加快这如果计数也没有必须要确切喜欢它似乎是在你的情况.

而不是获得准确的计数(大表):

SELECT count(*) AS exact_count FROM myschema.mytable;
Run Code Online (Sandbox Code Playgroud)

你得到这样的近似估计(非常快):

SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';
Run Code Online (Sandbox Code Playgroud)

估计的接近程度取决于您是否ANALYZE足够运行.它通常非常接近.
请参阅PostgreSQL Wiki常见问题解答.
或者计数(*)性能的专用维基页面.

更好

PostgreSQL的维基文章一个有点草率.它忽略了在一个数据库中可能存在多个同名表的可能性 - 在不同的模式中.为此解释:

SELECT c.reltuples::bigint AS estimate
FROM   pg_class c
JOIN   pg_namespace n ON n.oid = c.relnamespace
WHERE  c.relname = 'mytable'
AND    n.nspname = 'myschema'
Run Code Online (Sandbox Code Playgroud)

或者更好

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;
Run Code Online (Sandbox Code Playgroud)

更快,更简单,更安全,更优雅.请参阅对象标识符类型手册.

to_regclass('myschema.mytable')在Postgres 9.4+中使用以避免无效表名的例外:


TABLESAMPLE SYSTEM (n) 在Postgres 9.5+

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Run Code Online (Sandbox Code Playgroud)

@a_horse评论的那样,SELECT如果pg_class由于某种原因统计信息不够充分,那么新添加的命令子句可能会很有用.例如:

  • 没有autovacuum跑.
  • 一个大INSERT或后立即DELETE.
  • TEMPORARY表格(未涵盖autovacuum).

这仅查看随机n%(1在示例中)块的选择并计算其中的行.更大的样本会增加成本并减少错误.准确性取决于更多因素:

  • 行大小的分布.如果给定的块碰巧比通常的行保持更宽,则计数低于平常等.
  • FILLFACTOR每个块都有死元组或占用空间.如果在桌子上分布不均匀,估计可能会被取消.
  • 一般舍入错误.

在大多数情况下,估计pg_class将更快,更准确.

回答实际问题

首先,我需要知道该表中的行数,如果总计数大于某个预定义的常量,

无论是......

......当计数通过我的常量值时,它可能会停止计数(而不是等待完成计数以通知行计数更大).

是.您可以使用子查询LIMIT:

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Run Code Online (Sandbox Code Playgroud)

Postgres 实际上停止计数超出给定的限制,你得到最多n行的精确和当前计数(在示例中为500000),否则为n.然而,并不像估计的那么快.pg_class

  • 我最终使用改进的查询更新了Postgres Wiki页面. (7认同)
  • 使用`tablesample`子句可以快速获得9.5估计:例如`select count(*)*100作为来自mytable tablesample system(1)的cnt;` (4认同)
  • @ErwinBrandstetter 如果我有一个像这样的查询“SELECT COUNT(*) FROM users where last_name='a';”怎么办? (2认同)
  • @ErwinBrandstetter意识到这个问题很旧,但是如果您将查询包装在子查询中,那么限制会仍然有效,还是将整个子查询执行,然后限制在外部查询中。`SELECT count(*)FROM(从(SELECT 1 FROM令牌)查询中选择*)LIMIT 500000)limited_query;`(我问是因为我试图从任意查询中获得一个可能已经包含limit子句的计数) (2认同)

Fli*_*mzy 11

我在postgres应用程序中执行了一次运行:

EXPLAIN SELECT * FROM foo;
Run Code Online (Sandbox Code Playgroud)

然后使用正则表达式或类似逻辑检查输出.对于一个简单的SELECT*,第一行输出应该如下所示:

Seq Scan on uids  (cost=0.00..1.21 rows=8 width=75)
Run Code Online (Sandbox Code Playgroud)

您可以使用该rows=(\d+)值作为将返回的行数的粗略估计,然后仅SELECT COUNT(*)在估计值小于1.5倍阈值(或您认为对您的应用程序有意义的任何数字)时执行.

根据查询的复杂程度,此数字可能会变得越来越不准确.事实上,在我的应用程序中,当我们添加连接和复杂条件时,它变得非常不准确,它完全没有价值,甚至知道如何在100的幂内我们返回多少行,所以我们不得不放弃该策略.

但是如果你的查询很简单,Pg可以在一定的合理误差范围内预测它将返回多少行,它可能对你有用.


Anv*_*esh 6

参考资料取自此博客。

您可以使用下面的查询来查找行数。

使用 pg_class:

 SELECT reltuples::bigint AS EstimatedCount
    FROM   pg_class
    WHERE  oid = 'public.TableName'::regclass;
Run Code Online (Sandbox Code Playgroud)

使用 pg_stat_user_tables:

SELECT 
    schemaname
    ,relname
    ,n_live_tup AS EstimatedCount 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC;
Run Code Online (Sandbox Code Playgroud)