我可以使用SELECT count(*)FROM表。但是如果我的常数值是500,000,并且我在表中有5,000,000行,则对所有行计数将浪费很多时间。
一旦我的常数值超过,是否可以停止计数?
我只需要确切的行数,只要它低于给定的限制。否则,如果计数高于限制,我使用极限值,并希望答案尽可能快。
这样的东西:
SELECT text,count(*),percentual_calculus() FROM token GROUP BY text ORDER BY count DESC;
而不是获取确切的计数(慢表与大表):
SELECT count(*) AS exact_count FROM myschema.mytable;
你得到这样一个接近的估计(非常快):
SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';
估计的接近程度取决于你是否足够运行ANALYZE
。它通常非常接近。
见PostgreSQL Wiki FAQ。
或the dedicated wiki page for count(*) performance。
更好
Postgresql Wiki中的文章是有点马虎。它忽略了在一个数据库中可以有多个相同名称的表的可能性 – 在不同的模式中。为了解释:
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;
更快,更简单,更安全,更优雅。参见Object Identifier Types上的手册。
在Postgres 9.4中使用to_regclass(‘myschema.mytable’),以避免无效表名的异常:
> How to check if a table exists in a given schema
TABLESAMPLE SYSTEM (n)
在Postgres 9.5
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
像@a_horse commented一样,如果pg_class中的统计信息由于某种原因而不够新,则SELECT命令的新添加子句可能很有用。例如:
>没有自动真空运行。
>在大INSERT或DELETE之后立即。
> TEMPORARY表(不包括自动真空)。
这只看到一个随机的n%(在示例中为1)选择块并计数其中的行。更大的样本增加了成本,并减少错误,你的选择。精度取决于更多的因素:
>行大小的分布。如果给定块比正常行更宽,则计数比通常低。
>死的元组或FILLFACTOR占用每个块的空间。如果在表中不均匀分布,则估计可能关闭。
>一般舍入误差。
在大多数情况下,pg_class的估计将更快更准确。
回答实际问题
First,I need to know the number of rows in that table,if the total
count is greater than some predefined constant,
是否…
… is possible at the moment the count pass my constant value,it will
stop the counting (and not wait to finish the counting to inform the
row count is greater).
是。您可以使用带有LIMIT的子查询:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres实际上停止计数超过给定的限制,你获得一个精确和当前计数最多n行(在示例中为500000),否则n。没有几乎像pg_class中的估计一样快。