38

We need to count the number of rows in a PostgreSQL table. In our case, no conditions need to be met, and it would be perfectly acceptable to get a row estimate if that significantly improved query speed.

Basically, we want select count(id) from <table> to run as fast as possible, even if that implies not getting exact results.

4

6 回答 6

63

对于一个非常快速的估计:

SELECT reltuples FROM pg_class WHERE relname = 'my_table';

不过,有几个警告。一方面,relname不一定是唯一的pg_classrelname在数据库的多个模式中可以有多个相同的表。要明确:

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

如果您不对表名进行模式限定,则强制转换regclass观察当前search_path以选择最佳匹配。如果该表在任何模式中都不存在(或看不到),search_path您会收到一条错误消息。请参阅手册中的对象标识符类型

演员可以很好地bigint格式化real数字,特别是对于大计数。

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

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

于 2013-01-28T21:53:35.743 回答
13

大表的计数很慢,因此您可以通过以下方式进行近似估计:

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

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

  • reltuples是表中的一列pg_class,它包含有关“表中的行数。这只是规划器使用的估计值。它由 VACUUM、ANALYZE 和一些 DDL 命令(如 CREATE INDEX)更新”(手动)
  • 目录对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
于 2013-01-28T20:31:46.320 回答
6

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

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

select reltuples from pg_class where relname='tablename';
于 2013-01-28T20:28:57.793 回答
3

您可以通过简单地使用触发器 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(*) 来初始化第一条记录

于 2015-01-29T15:56:58.477 回答
2

您可以从系统表“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';
于 2013-01-28T20:33:57.250 回答
0

如果您的数据库很小,您可以像@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)
于 2016-12-18T18:49:19.173 回答