SELECT count(*) FROM table_name;
但我想看到所有表格的行数,然后按照行数排序,以便了解我的所有表格有多大。
SELECT count(*) FROM table_name;
但我想看到所有表格的行数,然后按照行数排序,以便了解我的所有表格有多大。
有三种方法可以获得这种类型的计数,每种方法都有其优缺点。
如果你想要一个真实的计数,你必须像你对每个表所使用的那个 SELECT 语句一样执行。这是因为PostgreSQL在行本身中保存行可见性信息,而不是在任何其他地方,因此任何准确的计数只能相对于某些事务。你得到的是该事务在执行时看到的内容的计数点。你可以自动化这个过程以针对数据库中的每个表运行,但你可能不需要那么高的精度或者想等那么长时间。
WITH tbl AS
(SELECT table_schema,
TABLE_NAME
FROM information_schema.tables
WHERE TABLE_NAME not like 'pg_%'
AND table_schema in ('public'))
SELECT table_schema,
TABLE_NAME,
(xpath('/row/c/text()', query_to_xml(format('select count(*) as c from %I.%I', table_schema, TABLE_NAME), FALSE, TRUE, '')))[1]::text::int AS rows_n
FROM tbl
ORDER BY rows_n DESC;
第二种方法指出,统计收集器大致跟踪有多少行是“活跃的”(未被删除或被后续更新所淘汰)。这个值在高负载情况下可能会有点偏差,但通常是一个很好的估算:
SELECT schemaname,relname,n_live_tup
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
这还可以显示有多少行是失效的,这本身就是一个有趣的数字要监控。
第三种方法是注意到系统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 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()
函数。
xpath()
函数只适用于一个 单独的 行- count(*)
的结果。 - user330315要获取估计值,请参见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 s.n,rowcount_all(s.n) from (values ('schema1'),('schema2')) as s(n)
)
SELECT schema_name,(tbl).* FROM rc;
这将生成一个包含模式、表和行数的三列输出。
现在,其他答案中存在一些问题,而此函数避免了这些问题:
表和架构名称不能在可执行的 SQL 中注入,除非使用quote_ident
或更现代的format()
函数及其%I
格式字符串进行引用。否则,一些恶意人可能命名他们的表为tablename;DROP TABLE other_table
,这是完全有效的作为表名。
即使没有SQL注入和有趣的字符问题,表名可能存在不同大小写的变体。如果一个表名为ABCD
,另一个表名为abcd
,那么SELECT count(*) FROM ...
必须使用带引号的名称,否则它将跳过ABCD
并将abcd
计数两次。格式的%I
会自动执行此操作。
在旧版本的Postgres中,information_schema.tables
列表中包含自定义复合类型以及表,即使table_type为 'BASE TABLE'
。因此,我们不能在information_schema.tables
上迭代,否则我们会冒险执行select count(*) from name_of_composite_type
,这将失败。然而,pg_class where relkind='r'
应该始终正常工作。
COUNT()的类型为bigint
,而不是int
。可能存在超过21.5亿行的表(虽然在这些表上运行count(*)是个坏主意)。
一个永久类型无需为一个函数创建,即可返回具有多个列的结果集。RETURNS TABLE(definition...)
是更好的选择。
如果您正在尝试评估需要哪个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
然后运行一个正则表达式搜索和替换,如下所示:
^[^|]*\|\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
[..]
select '$1', count(*) from $1 union/g
- chuck/g
(保留union
)并在末尾添加一个分号(;
)。不要忘记在分号之前删除最后一个union
。 - chuckunion
。这就是我的意思 :) 我加上了“last”一词以澄清。 - Aur Sarafselect '$1',count(*) from $1 union
。 - Karol Selak如果您不介意潜在的过时数据,您可以访问与查询优化器使用相同的统计信息。
类似于:
SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
ANALYZE
,那么统计数据可能会严重偏差。这取决于数据库负载和数据库的配置(如果统计数据更新得更频繁,统计数据将更准确,但可能会降低运行时性能)。最终,获取准确数据的唯一方法是对所有表运行select count(*) from table
。 - ig0774简单的两个步骤:
(注意:不需要更改任何内容-只需复制粘贴)
1. 创建函数
create function
cnt_rows(schema text, tablename text) returns integer
as
$body$
declare
result integer;
query varchar;
begin
query := 'SELECT count(1) FROM ' || schema || '.' || tablename;
execute query into result;
return result;
end;
$body$
language plpgsql;
2. 运行此查询以获取所有表的行数
select sum(cnt_rows) as total_no_of_rows from (select
cnt_rows(table_schema, table_name)
from information_schema.tables
where
table_schema not in ('pg_catalog', 'information_schema')
and table_type='BASE TABLE') as subq;
或者
按表获取行数
select
table_schema,
table_name,
cnt_rows(table_schema, table_name)
from information_schema.tables
where
table_schema not in ('pg_catalog', 'information_schema')
and table_type='BASE TABLE'
order by 3 desc;
不确定在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
select count(*) from table_name;
相同。 - Noach MagedmanSELECT COUNT(*) FROM all_tables;
! - undefinedwith tbl as (
SELECT table_schema,table_name
FROM information_schema.tables
WHERE table_name not like 'pg_%' AND table_schema IN ('public')
)
SELECT
table_schema,
table_name,
(xpath('/row/c/text()',
query_to_xml(format('select count(*) AS c from %I.%I', table_schema, table_name),
false,
true,
'')))[1]::text::int AS rows_n
FROM tbl ORDER BY 3 DESC;
感谢@a_horse_with_no_name
通常我不太依赖统计数据,特别是在 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;
dsql2('select count(*) from livescreen.'||table_name)
或者最好将其转换为自己的函数。 - jakub-olczyk这对我有用
按照n_live_tup降序排序,选择pg_stat_user_tables中的schemaname、relname和n_live_tup。
with tbl as (SELECT table_schema, table_name FROM information_schema.tables where table_name not like 'pg_%' and table_schema in ('public')) select table_schema, table_name, (xpath('/row/c/text()', query_to_xml(format('select count(*) as c from %I.%I', table_schema, table_name), false, true, '')))[1]::text::int as rows_n from tbl ORDER BY 3 DESC;
请注意,我会尽力使翻译通俗易懂,但不会更改原文的含义或提供额外的解释。 - estanin_live_tup
?我的Redshift数据库缺少该列。它是Postgres 8.0.2的一个派生版本。 - Iain Samuel McLean Elderpg_stat_user_tables
)在我的情况下返回的大部分是0,因为从未运行过ANALYZE
。我不想在每个模式/表上运行ANALYZE
并永远等待答案,因此我首先使用“第三种方法”检查了结果,那个方法(使用pg_class
)返回非常准确的计数。 - Brian D