在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+中使用可避免无效表名的例外情况:
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
就像@a_horse commented一样,SELECT
如果pg_class
由于某些原因当前的统计信息不足,则为该命令新添加的子句可能很有用。例如:
- 没有
autovacuum
运行。
- 大
INSERT
或DELETE
。
TEMPORARY
表格(未被涵盖autovacuum
)。
这只会查看随机选择的n%(1
在示例中)的块并计算其中的行。选择更大的样本会增加成本并减少错误。准确性取决于更多因素:
- 行大小分布。如果给定的块恰好比平常的行宽,则计数比平常的低,等等。
- 死元组或
FILLFACTOR
每个块占用空间。如果整个表分布不均,则估计值可能会不正确。
- 一般舍入错误。
在大多数情况下,来自的估计pg_class
会更快,更准确。
回答实际问题
首先,我需要知道该表中的行数,如果总计数大于某个预定义常量,
以及是否...
...在计数超过我的恒定值时是可能的,它将停止计数(而不是等待完成计数以告知行计数更大)。
是。您可以将子查询与结合使用LIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres 实际上停止计数超过给定的限制,您将获得最多n行(在本示例中为500000)的准确和当前计数,否则为n。但是,速度不及中的估算速度。pg_class