众所周知,在PostgreSQL中,计算大表中的行速度很慢.MVCC型号需要完整的活动行数才能获得精确的数字.如果not的计数必须是exact,就像你的情况一样,那么speed this up dramatically有变通办法.
(请记住,在并发写负载下,即使是"精确"计数也可能在到达时失效.)
精确计数
Slow for big tables.
With concurrent write operations, it may be outdated the moment you get it.
SELECT count(*) AS exact_count FROM myschema.mytable;
Estimate
非常fast:
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
通常,估计值非常接近.距离有多近取决于ANALYZE
或VACUUM
是否足够运行,其中"足够"由表的写入活动级别定义.
Safer estimate
以上内容忽略了在一个数据库中使用相同名称的多个表的可能性——在不同的模式中.为了说明这一点:
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';
演员阵容为bigint
,很好地格式化了real
的数字,特别是对于大计数.
更好的估计
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
更快、更简单、更安全、更优雅.参见Object Identifier Types上的手册.
在Postgres 9.4+中,将'myschema.mytable'::regclass
替换为to_regclass('myschema.mytable')
,以不获取任何内容,而不是无效表名的异常.见:
更好的估计(几乎不增加成本)
我们可以做博士后规划师做的事情.引用Row Estimation Examples in the manual条:
这些数字是上一个VACUUM
或ANALYZE
的最新数字
Postgres使用src/backend/utils/adt/plancat.c
中定义的estimate_rel_size
,这也涵盖了pg_class
中没有数据的情况,因为关系从未被清空.我们可以在SQL中执行类似的操作:
Minimal form
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
Safe and explicit
SELECT (CASE WHEN c.reltuples < 0 THEN NULL -- never vacuumed
WHEN c.relpages = 0 THEN float8 '0' -- empty table
ELSE c.reltuples / c.relpages END
* (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
)::bigint
FROM pg_class c
WHERE c.oid = 'myschema.mytable'::regclass; -- schema-qualified table here
不会与空桌子和从未见过VACUUM
或ANALYZE
的桌子决裂.The manual on pg_class
:
如果该表从未被抽真空或分析过,则reltuples
包含-1
,表示行数未知.
如果该查询返回NULL
,则对该表运行ANALYZE
或VACUUM
并重复.(或者,您也可以像Postgres那样基于列类型估计行宽,但这既繁琐又容易出错.)
如果此查询返回0
,则表似乎为空.但我想确认一下.(也许可以判断一下你的autovacuum
设置.)
通常,block_size
等于8192.current_setting('block_size')::int
涵盖了罕见的例外情况.
表和模式限定使其不受任何search_path
和范围的影响.
不管是哪种方式,查询都会持续进行<;对我来说是0.1毫秒.
更多网络资源:
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
与@a_horse commented一样,如果pg_class
中的统计信息由于某种原因不够及时,SELECT
命令的added子句也会很有用.例如:
- 没有
autovacuum
人在 run .
- 就在
INSERT
/UPDATE
/DELETE
大爆炸之后.
TEMPORARY
张桌子(autovacuum
不包括在内).
这只会查看随机 Select 的n%(示例中为1
)块,并对其中的行进行计数.更大的样本会增加成本并减少误差,你可以 Select .准确性取决于更多因素:
- 行大小的分布.如果一个给定的块恰好包含比平常更宽的行,那么计数就会比平常低,等等.
- 死元组或
FILLFACTOR
占用每个块的空间.如果在整个表格中分布不均,估计值可能会偏离.
- 一般舍入误差.
通常,从pg_class
开始的估计会更快、更准确.
对实际问题的回答
首先,我需要知道表中的行数,如果总数
以及是否...
... 当计数通过我的常量值时,它将是可能的
Yes.你可以使用subquery with 100:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres actually stops counting超出给定限制,最多n行(本例中为500000行)的计数为exact and current,否则为n.不过,速度远不及pg_class
年的估计.