如何加快计算 PostgreSQL 表中的行数?

Posted

技术标签:

【中文标题】如何加快计算 PostgreSQL 表中的行数?【英文标题】:How do I speed up counting rows in a PostgreSQL table? 【发布时间】:2013-01-12 06:58:17 【问题描述】:

我们需要计算 PostgreSQL 表中的行数。在我们的例子中,不需要满足任何条件,如果这样可以显着提高查询速度,那么获得行估计是完全可以接受的。

基本上,我们希望select count(id) from <table> 尽可能快地运行,即使这意味着无法获得准确的结果。

【问题讨论】:

wiki.postgresql.org/wiki/Slow_Counting @PavelStehule 感谢该链接,我不知道 PG9.2 的变化提高了 count() 的性能 Fast way to discover the row count of a table的可能重复 【参考方案1】:

快速估算:

SELECT reltuples FROM pg_class WHERE relname = 'my_table';

不过,有几个注意事项。一方面,relnamepg_class 中不一定是唯一的。在数据库的多个模式中可以有多个具有相同relname 的表。明确一点:

SELECT reltuples::bigint FROM pg_class WHERE oid = 'my_schema.my_table'::regclass;

如果您不对表名进行模式限定,则转换为 regclass 会观察当前的 search_path 以选择最佳匹配。如果表在search_path 的任何模式中都不存在(或看不到),您会收到一条错误消息。见Object Identifier Types in the manual。

转换为bigint 可以很好地格式化real 数字,尤其是对于大计数。

另外,reltuples 可能或多或少已经过时。有办法在一定程度上弥补这一点。使用新的和改进的选项查看稍后的答案:

Fast way to discover the row count of a table in PostgreSQL

pg_stat_user_tables 上的查询要慢很多倍(尽管仍然比完整计数快得多),因为这是对几个表的视图。

【讨论】:

不错的 +1。关于我们如何加快具有搜索查询的 postgres 中的行计数的任何想法? @varunvlalan:请将问题作为问题提出(并提供必要的细节以使其清楚)。评论不是地方。您可以随时链接到这个以获取上下文。 这个查询给出了一个估计值。如果我想构建一个需要精确记录数的报告,可以在数十万条记录的表上运行? '已经看到 postgre 最多需要 13 秒来计算 20000 条记录!我可以相信 @Giox:我也不敢相信。 20k 行的 13 秒远远超出正常范围 - 表明您的数据库存在问题。不应该超过几个毫秒。请提出一个问题,提供必要的详细信息。您始终可以链接到此以获取上下文。评论不是地方。您可以在此处发表简短评论 (or maybe here?) 以链接到相关问题并引起我的注意。 这个查询给了我 415K,但是 COUNT(*) 返回 8M。【参考方案2】:

如果您的数据库很小,您可以像@mike-sherrill-cat-recall 建议的那样获得所有表的估计值。不过,此命令将列出所有表。

SELECT schemaname,relname,n_live_tup 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC;

输出会是这样的:

 schemaname |      relname       | n_live_tup
------------+--------------------+------------
 public     | items              |      21806
 public     | tags               |      11213
 public     | sessions           |       3269
 public     | users              |        266
 public     | shops              |        259
 public     | quantities         |         34
 public     | schema_migrations  |         30
 public     | locations          |          8
(8 rows)

【讨论】:

【参考方案3】:

除了在索引字段上运行 COUNT() (希望是 'id' ) - 下一个最好的事情是使用 INSERT 上的触发器实际缓存某个表中的行数。当然,您将改为检查缓存。

对于近似值,您可以试试这个(来自https://wiki.postgresql.org/wiki/Count_estimate):

select reltuples from pg_class where relname='tablename';

【讨论】:

【参考方案4】:

您可以通过简单地使用触发器 AFTER INSERT OR DELETE 来询问表中计数的确切值 像这样的

CREATE TABLE  tcounter(id serial primary key,table_schema text, table_name text, count serial);

insert into tcounter(table_schema, table_name,count) select 'my_schema', 'my_table', count(*) from my_schema.my_table;

并使用触发器

CREATE OR REPLACE FUNCTION ex_count()
RETURNS trigger AS
$BODY$
BEGIN
    IF (TG_OP='INSERT') THEN
      UPDATE tcounter set count = count + 1 where table_schema = TG_TABLE_SCHEMA::TEXT and table_name = TG_TABLE_NAME::TEXT;
    ELSIF  (TG_OP='DELETE') THEN
      UPDATE tcounter set count = count - 1 where table_schema = TG_TABLE_SCHEMA::TEXT and table_name = TG_TABLE_NAME::TEXT;
    END IF;
RETURN NEW;
END$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

CREATE TRIGGER tg_counter  AFTER INSERT OR DELETE
  ON my_schema.my_table  FOR EACH ROW  EXECUTE PROCEDURE ex_count();

并要求计数

select * from tcounter where table_schema =  'my_schema' and table_name = 'my_table'

这意味着您选择 count(*) 一次来初始化第一条记录

【讨论】:

【参考方案5】:

大表的计数很慢,因此您可以通过这种方式得到一个接近的估计:

SELECT reltuples::bigint AS estimate 
FROM pg_class 
WHERE relname='tableName';

而且它的速度非常快,结果不是浮动的,但仍然是一个接近的估计。

reltuplespg_class 表中的一列,它包含有关“表中的行数”的数据。这只是规划器使用的估计值。它由 VACUUM、ANALYZE 和一些 DDL 命令(如 CREATE)更新索引”(手动) 目录pg_class 对表和大多数其他具有列或与表类似的所有内容进行编目。这包括索引(另见 pg_index)、序列、视图、复合类型和一些特殊关系(手动) “为什么“SELECT count(*) FROM bigtable;”很慢? :http://wiki.postgresql.org/wiki/FAQ#Why_is_.22SELECT_count.28.2A.29_FROM_bigtable.3B.22_slow.3F

【讨论】:

很好,::bigint 部分避免了表大小 > 4B 或类似阈值的溢出,谢谢! 如果我愿意,是否可以添加 where 子句?【参考方案6】:

您可以从系统表“pg_stat_user_tables”中得到一个估计值。

select schemaname, relname, n_live_tup 
from pg_stat_user_tables 
where schemaname = 'your_schema_name'
and relname = 'your_table_name';

【讨论】:

以上是关于如何加快计算 PostgreSQL 表中的行数?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:计算表中的行数

如何计算小于 Hive 表中特定行的行数?

PostgreSQL:随时间变化的行数

SQL 计算表中的行数

如何使用 PHP 获取 MySQL 表中的行数?

选择 Count (distinct col) 查询以显示结果中的行数和列数 - postgresql