我需要知道表中的行数来计算百分比。如果总计数大于某个预定义常量,我将使用常量值。否则,我将使用实际的行数。
我可以使用SELECT count(*) FROM table
。但是如果我的常量值是 500,000 并且我的表中有 5,000,000,000 行,那么计算所有行会浪费很多时间。
一旦超过常数值,是否可以停止计数?
只要它低于给定的限制,我才需要确切的行数。否则,如果计数高于限制,我会使用限制值,并希望尽快得到答案。
这样的事情:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
答案 0 :(得分:174)
计算 big 表中的行在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
或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')
以避免无效表名的例外:
TABLESAMPLE SYSTEM (n)
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
的估算值会更快,更准确。
首先,我需要知道该表中的行数(如果是总数) count大于某个预定义常量
是否...
...当计数通过我的常数值时,它是可能的 停止计数(而不是等到完成计数通知 行数更多)。
是。您可以将{strong>子查询与LIMIT
一起使用:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Postgres 实际上停止计数超出给定限制,您获得 n 行的精确和当前计数(示例中为500000) ),否则 n 。但不如pg_class
中的估算速度快。
答案 1 :(得分:9)
我在postgres应用中执行了一次运行:
EXPLAIN SELECT * FROM foo;
然后用正则表达式或类似逻辑检查输出。对于简单的SELECT *,第一行输出应如下所示:
Seq Scan on uids (cost=0.00..1.21 rows=8 width=75)
您可以使用rows=(\d+)
值作为返回行数的粗略估算值,如果估算值低于您的阈值的1.5倍,则只能使用实际值SELECT COUNT(*)
(或您认为对您的申请有意义的任何数字)。
根据查询的复杂程度,此数字可能会变得越来越不准确。事实上,在我的应用程序中,当我们添加连接和复杂条件时,它变得非常不准确,它完全没有价值,甚至知道如何在100的幂内我们返回多少行,所以我们不得不放弃该策略。
但是如果你的查询很简单,Pg可以在一定的合理误差范围内预测它会返回多少行,那么它可能适合你。
答案 2 :(得分:1)
在Oracle中,您可以使用rownum
来限制返回的行数。我猜测其他SQL中也存在类似的构造。因此,对于您提供的示例,您可以将返回的行数限制为500001,然后应用count(*)
:
SELECT (case when cnt > 500000 then 500000 else cnt end) myCnt
FROM (SELECT count(*) cnt FROM table WHERE rownum<=500001)
答案 3 :(得分:1)
您可以通过以下查询获得计数(不带*或任何列名)。
select from table_name;
答案 4 :(得分:0)
文本列有多宽?
使用GROUP BY,您无法避免数据扫描(至少是索引扫描)。
我建议:
如果可能,请更改架构以删除文本数据的重复。这样,计数将发生在'many'表中的狭窄外键字段上。
或者,使用文本的HASH创建生成的列,然后使用哈希列GROUP BY。 同样,这是为了减少工作量(扫描窄列索引)
编辑:
您的原始问题与您的编辑不完全匹配。我不确定您是否知道COUNT与GROUP BY一起使用时,将返回每组的项目数,而不是整个表中的项目数。
答案 5 :(得分:0)
Reference taken from this Blog.
您可以使用以下查询来查找行数。
使用pg_class:
SELECT reltuples::bigint AS EstimatedCount
FROM pg_class
WHERE oid = 'public.TableName'::regclass;
使用pg_stat_user_tables:
SELECT
schemaname
,relname
,n_live_tup AS EstimatedCount
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
答案 6 :(得分:-1)