你如何findPostgres中所有表格的行数

我正在寻找一种方法来查找Postgres中所有表的行数。 我知道我可以一次做这一张桌子:

SELECT count(*) FROM table_name; 

但是我希望看到所有表格的行数,然后通过sorting来了解我的表格有多大。

有三种方法可以获得这种计数,每种方法都有自己的权衡。

如果你想要一个真正的计数,你必须执行SELECT语句,就像你对每个表所使用的那样。 这是因为PostgreSQL在行本身而不是其他地方保留行可见性信息,所以任何精确的计数只能是相对于某个事务。 你会得到这个事务在执行时看到的内容。 您可以自动执行此操作,以针对数据库中的每个表运行,但您可能不需要那么高的准确性,或者需要等待很长时间。

第二种方法指出,统计信息收集器可以随时跟踪有多less行是“活的”(未被删除或被以后的更新过时)。 在繁重的工作中,这个数值可能会有点偏差,但通常是一个很好的估计:

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

这也可以告诉你有多less行死了,这本身是一个有趣的数字来监视。

第三种方法是注意,系统ANALYZE命令(由PostgreSQL 8.3定期执行的autovacuum进程来更新表的统计信息)也计算一个行估计值。 你可以像这样抓住那个:

 SELECT nspname AS schemaname,relname,reltuples FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND relkind='r' ORDER BY reltuples DESC; 

这些查询哪个更好用是很难说的。 通常我会根据是否还有更多有用的信息来做决定,这些信息我也想在pg_class或pg_stat_user_tables中使用。 基本计算的目的只是为了看看一般事情有多大,要么足够准确。

如果您不介意潜在的陈旧数据,则可以访问查询优化器使用的统计信息 。

就像是:

 SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables; 

要得到估计,请参阅Greg Smith的答案 。

为了得到确切的数字,到目前为止的其他答案困扰着一些问题,其中一些是严重的(见下文)。 这是一个希望更好的版本:

 CREATE FUNCTION rowcount_all(schema_name text default 'public') RETURNS table(table_name text, cnt bigint) as $$ declare table_name text; begin for table_name in SELECT c.relname FROM pg_class c JOIN pg_namespace s ON (c.relnamespace=s.oid) WHERE c.relkind = 'r' AND s.nspname=schema_name LOOP RETURN QUERY EXECUTE format('select cast(%L as text),count(*) from %I.%I', table_name, schema_name, table_name); END LOOP; end $$ language plpgsql; 

它将模式名称作为参数,如果没有给出参数,则使用public

要使用特定的模式列表或来自查询的列表而不修改函数,可以在查询中调用它,如下所示:

 WITH rc(schema_name,tbl) AS ( select sn,rowcount_all(sn) from (values ('schema1'),('schema2')) as s(n) ) SELECT schema_name,(tbl).* FROM rc; 

这将产生一个3列的输出,包括模式,表格和行数。

现在这里有一些问题在其他答案,这个function避免:

  • 表格和模式名称不应该被引用到可执行的SQL中,而不用引用quote_ident或带有更新的format()函数及其%I格式的string。 否则,一些恶意的人可能会将他们的表名称tablename;DROP TABLE other_table作为表名完全有效。

  • 即使没有SQL注入和有趣的字符问题,表名也可能以大小写不同的变体存在。 如果一个表名为ABCD ,另一个为abcd ,则SELECT count(*) FROM...必须使用带引号的名称,否则将跳过ABCD并计算两次abcd 。 格式的%I自动执行此操作。

  • 除了表格, information_schema.tables列出了自定义的复合types,即使table_type是'BASE TABLE' (!)。 因此,我们无法迭代information_schema.tables ,否则我们冒着select count(*) from name_of_composite_typeselect count(*) from name_of_composite_type风险,并且会失败。 OTOH pg_class where relkind='r'应该总是正常工作。

  • COUNT()的types是bigint ,而不是int 。 有超过21.5亿行的表可能存在(虽然运行一个计数(*)是一个坏主意)。

  • 不需要为函数创build永久types来返回具有多列的结果集。 RETURNS TABLE(definition...)是一个更好的select。

这是一个解决scheme,不需要函数来获得每个表的准确计数:

 select table_schema, table_name, (xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count from ( select table_name, table_schema, query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count from information_schema.tables where table_schema = 'public' --<< change here for the schema you want ) t 

query_to_xml将运行传递的SQL查询并返回一个带有结果(该表的行数)的XML。 然后,外部xpath()将从该xml中提取计数信息并将其转换为数字

派生表并不是真的必要,但是使得xpath()更容易理解 – 否则整个query_to_xml()需要传递给xpath()函数。

不知道bash中的答案是否可以接受,但是FWIW …

 PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \" SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='public' \"" TABLENAMES=$(export PGPASSWORD=test; eval "$PGCOMMAND") for TABLENAME in $TABLENAMES; do PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \" SELECT '$TABLENAME', count(*) FROM $TABLENAME \"" eval "$PGCOMMAND" done 

我不记得我从哪里收集这个url。 但希望这应该帮助你:

 CREATE TYPE table_count AS (table_name TEXT, num_rows INTEGER); CREATE OR REPLACE FUNCTION count_em_all () RETURNS SETOF table_count AS ' DECLARE the_count RECORD; t_name RECORD; r table_count%ROWTYPE; BEGIN FOR t_name IN SELECT c.relname FROM pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = ''r'' AND n.nspname = ''public'' ORDER BY 1 LOOP FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.relname LOOP END LOOP; r.table_name := t_name.relname; r.num_rows := the_count.count; RETURN NEXT r; END LOOP; RETURN; END; ' LANGUAGE plpgsql; 

执行select count_em_all(); 应该让你所有的表的行数。

我通常不会依赖统计数据,特别是在PostgreSQL中。

 SELECT table_name, dsql2('select count(*) from '||table_name) as rownum FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='livescreen' ORDER BY 2 DESC; 
 CREATE OR REPLACE FUNCTION dsql2(i_text text) RETURNS int AS $BODY$ Declare v_val int; BEGIN execute i_text into v_val; return v_val; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; 

我做了一个小的变化,包括所有的表格,也用于非公开的表格。

 CREATE TYPE table_count AS (table_schema TEXT,table_name TEXT, num_rows INTEGER); CREATE OR REPLACE FUNCTION count_em_all () RETURNS SETOF table_count AS ' DECLARE the_count RECORD; t_name RECORD; r table_count%ROWTYPE; BEGIN FOR t_name IN SELECT table_schema,table_name FROM information_schema.tables where table_schema !=''pg_catalog'' and table_schema !=''information_schema'' ORDER BY 1,2 LOOP FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.table_schema||''.''||t_name.table_name LOOP END LOOP; r.table_schema := t_name.table_schema; r.table_name := t_name.table_name; r.num_rows := the_count.count; RETURN NEXT r; END LOOP; RETURN; END; ' LANGUAGE plpgsql; 

使用select count_em_all(); 称它。

希望你find这个有用的。 保罗

对于那些试图评估他们所需要的Heroku计划的人来说,这是一个非常实际的答案,并且迫不及待地想要更新Heroku的缓慢行数:

基本上你想在psql运行\dt ,把结果复制到你最喜欢的文本编辑器(它看起来像这样:

  public | auth_group | table | axrsosvelhutvw public | auth_group_permissions | table | axrsosvelhutvw public | auth_permission | table | axrsosvelhutvw public | auth_user | table | axrsosvelhutvw public | auth_user_groups | table | axrsosvelhutvw public | auth_user_user_permissions | table | axrsosvelhutvw public | background_task | table | axrsosvelhutvw public | django_admin_log | table | axrsosvelhutvw public | django_content_type | table | axrsosvelhutvw public | django_migrations | table | axrsosvelhutvw public | django_session | table | axrsosvelhutvw public | exercises_assignment | table | axrsosvelhutvw 

),然后运行一个正则expression式search,并像这样replace:

 ^[^|]*\|\s+([^|]*?)\s+\| table \|.*$ 

至:

 select '\1', count(*) from \1 union/g 

这会产生一些非常相似的东西:

 select 'auth_group', count(*) from auth_group union select 'auth_group_permissions', count(*) from auth_group_permissions union select 'auth_permission', count(*) from auth_permission union select 'auth_user', count(*) from auth_user union select 'auth_user_groups', count(*) from auth_user_groups union select 'auth_user_user_permissions', count(*) from auth_user_user_permissions union select 'background_task', count(*) from background_task union select 'django_admin_log', count(*) from django_admin_log union select 'django_content_type', count(*) from django_content_type union select 'django_migrations', count(*) from django_migrations union select 'django_session', count(*) from django_session ; 

(您需要删除union并手动在末尾添加分号)

psql运行,就完成了。

  ?column? | count --------------------------------+------- auth_group_permissions | 0 auth_user_user_permissions | 0 django_session | 1306 django_content_type | 17 auth_user_groups | 162 django_admin_log | 9106 django_migrations | 19 [..] 

我喜欢DanielVérité的回答 。 但是当你不能使用CREATE语句时,你可以使用bash解决scheme,或者,如果你是一个Windows用户,则可以使用powershell:

 # You don't need this if you have pgpass.conf $env:PGPASSWORD = "userpass" # Get table list $tables = & 'C:\Program Files\PostgreSQL\9.4\bin\psql.exe' -U user -w -d dbname -At -c "select table_name from information_schema.tables where table_type='BASE TABLE' AND table_schema='schema1'" foreach ($table in $tables) { & 'C:\path_to_postresql\bin\psql.exe' -U root -w -d dbname -At -c "select '$table', count(*) from $table" }