首页 文章

如何在Postgres中找到所有表的行数

提问于
浏览
303

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

SELECT count(*) FROM table_name;

但我希望看到所有表格的行数,然后按顺序排列,以了解我所有表格的大小 .

11 回答

  • 19

    不确定你是否接受答案 in 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
    
  • 1

    简单的两步:
    (注意:无需更改任何东西只需复制粘贴)
    1. create function

    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. Run this query to get rows count for all the tables

    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;
    

    or
    To get rows counts tablewise

    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
    
  • 6

    我做了一个小变化来包括所有表,也用于非公共表 .

    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(); 来调用它 .

    希望你觉得这很有用 . 保罗

  • 439

    我不记得我收集它的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(); 应该可以获得所有表的行数 .

  • 4

    要获得估算值,请参阅Greg Smith's answer .

    为了获得准确的计数,到目前为止的其他答案都存在一些问题,其中一些是严重的(见下文) . 这是一个希望更好的版本:

    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;
    

    这将产生一个3列输出,其中包含模式,表和行数 .

    现在这里是这个函数避免的其他答案中的一些问题:

    • 表和模式名称不应在没有引用的情况下注入可执行SQL,使用 quote_ident 或使用更现代的 format() 函数及其 %I 格式字符串 . 否则,某些恶意的人可能将他们的表命名为 tablename;DROP TABLE other_table ,这完全有效作为表名 .

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

    • information_schema.tables 除了表之外还列出了自定义复合类型,即使table_type是 'BASE TABLE' (!) . 因此,我们无法在 information_schema.tables 上进行迭代,否则我们会冒险 select count(*) from name_of_composite_type 而这将失败 . OTOH pg_class where relkind='r' 应该永远正常 .

    • COUNT()的类型是 bigint ,而不是 int . 可能存在超过21.5亿行的表(尽管对它们运行计数(*)是个坏主意) .

    • 不需要为函数创建永久类型以返回具有多个列的结果集 . RETURNS TABLE(definition...) 是一个更好的选择 .

  • 10

    我喜欢DanielVérité的answer . 但是当你不能使用CREATE语句时,你可以使用bash solution,或者如果你是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"
    }
    
  • 9

    如果您不介意可能过时的数据,可以access the same statistics used by the query optimizer .

    就像是:

    SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
    
  • 14

    对于那些试图评估他们需要哪个Heroku计划并且不能等待heroku的慢行计数器刷新的人来说,这个hacky,实用的答案:

    基本上你想在 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
    [..]
    
  • 5

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

    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() 函数 .

  • 18

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

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

    第二种方法指出,统计信息收集器随时跟踪大约有多少行是“活动”(未被删除或以后的更新废弃) . 在重度活动期间,这个值可能有点偏差,但通常是一个很好的估计:

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

    这也可以显示有多少行已死,这本身就是一个有趣的数字监控 .

    第三种方法是注意系统ANALYZE命令,它定期执行autovacuum进程,从PostgreSQL 8.3开始更新表统计信息,也可以计算行估计值 . 你可以像这样 grab 那个:

    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中使用 . 出于基本的计数目的,只是为了看到一般情况下的大事,要么应该足够准确 .

  • 1

    我通常不依赖于统计数据,特别是在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;
    

相关问题