在PostgreSQL中发现表的行数的快速方法

雷纳托·迪汉尼(Renato Dinhani)

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

我可以用SELECT count(*) FROM table但是,如果我的常量值为500,000,并且表中5,000,000,000行,则对所有行进行计数将浪费大量时间。

一旦超过我的恒定值,是否可以停止计数?

我只需要确切的行数,只要它低于给定的限制即可。否则,如果计数超出限制,我将改用限制值,并希望尽快给出答案。

像这样:

SELECT text,count(*), percentual_calculus()  
FROM token  
GROUP BY text  
ORDER BY count DESC;
欧文·布兰德斯特

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

而不是获得确切的计数(大表比较):

SELECT count(*) AS exact_count FROM myschema.mytable;

您会得到如下估算值(非常快):

SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';

估算的接近程度取决于您是否运行ANALYZE足够。通常很近。
请参阅PostgreSQL Wiki FAQ
用于count(*)性能的专用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'

还是更好

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;

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

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


TABLESAMPLE SYSTEM (n) 在Postgres 9.5+

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);

就像@a_horse commented一样SELECT如果pg_class由于某些原因当前的统计信息不足,则为该命令新添加的子句可能很有用例如:

  • 没有autovacuum运行。
  • INSERTDELETE
  • TEMPORARY表格(未被涵盖autovacuum)。

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

  • 行大小分布。如果给定的块恰好比平常的行宽,则计数比平常的低,等等。
  • 死元组或FILLFACTOR每个块占用空间。如果整个表分布不均,则估计值可能会不正确。
  • 一般舍入错误。

在大多数情况下,来自的估计pg_class会更快,更准确。

回答实际问题

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

以及是否...

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

是。您可以将子查询与结合使用LIMIT

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

Postgres实际上停止计数超过给定的限制,您将获得多达n行(在本示例中为500000)准确和当前计数,否则为n但是,速度不及中的估算速度pg_class

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章