487

Postgres のすべてのテーブルの行数を見つける方法を探しています。私はこれを一度に1つのテーブルで行うことができることを知っています:

SELECT count(*) FROM table_name;

しかし、すべてのテーブルの行数を確認し、それを並べ替えて、すべてのテーブルの大きさを把握したいと考えています。

4

19 に答える 19

728

この種のカウントを取得するには3つの方法があり、それぞれに独自のトレードオフがあります。

真のカウントが必要な場合は、各テーブルに対して使用したような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;

2番目のアプローチでは、統計コレクターは、いつでも「ライブ」(削除されたり、後の更新によって廃止されたりしない)行の大まかな数を追跡することに注意してください。この値は、アクティビティが多い場合は少しずれることがありますが、一般的には適切な見積もりです。

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

これは、死んでいる行の数を示すこともできます。これは、それ自体を監視するのに興味深い数です。

3番目の方法は、テーブル統計を更新するためにPostgreSQL 8.3の時点で自動バキュームプロセスによって定期的に実行されるシステムANALYZEコマンドも、行の見積もりを計算することに注意することです。あなたはこのようなものをつかむことができます:

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内で使用したいより有用な情報があるかどうかに基づいてその決定を行います。基本的なカウントの目的で、一般的にどれだけ大きいかを確認するために、どちらも十分に正確である必要があります。

于 2010-04-10T00:26:26.397 に答える
123

各テーブルの正確なカウントを取得するために関数を必要としないソリューションを次に示します。

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()ます。

于 2016-07-31T12:59:31.630 に答える
34

見積もりを取得するには、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;

これにより、スキーマ、テーブル、および行数を含む 3 列の出力が生成されます。

ここで、この関数が回避する他の回答の問題をいくつか示します。

  • テーブル名とスキーマ名は、引用符なしで実行可能な SQL に挿入しないでください。フォーマット文字列を使用quote_identした最新のformat()関数を使用する場合でも、使用する場合でも同様です。%Iそうしないと、悪意のある人物がtablename;DROP TABLE other_tableテーブル名として完全に有効な名前をテーブルに付ける可能性があります。

  • SQL インジェクションや変な文字の問題がなくても、テーブル名は大文字と小文字が異なるバリアントで存在する場合があります。テーブルに名前が付けられABCD、別のテーブルに名前が付けられている場合、引用符で囲まれた名前を使用する必要があります。そうしないと、スキップされabcdて2 回カウントされます。of 形式はこれを自動的に行います。SELECT count(*) FROM...ABCDabcd%I

  • information_schema.tablestable_type が'BASE TABLE'(!) の場合でも、テーブルに加えてカスタム複合型を一覧表示します。結果として、 を繰り返すことはできません。そうしないと、失敗するinformation_schema.tablesリスクがあります。select count(*) from name_of_composite_typeOTOHpg_class where relkind='r'は常に正常に動作するはずです。

  • COUNT() の型は でありbigint、 ではありませんint。21 億 5000 万行を超えるテーブルが存在する可能性があります (ただし、count(*) を実行することはお勧めできません)。

  • 関数が複数の列を持つ結果セットを返すために、永続型を作成する必要はありません。RETURNS TABLE(definition...)より良い代替手段です。

于 2015-02-25T01:37:09.063 に答える
24

古いデータの可能性が気にならない場合は、クエリ オプティマイザーで使用されるのと同じ統計にアクセスできます。

何かのようなもの:

SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
于 2010-04-07T23:57:44.873 に答える
14

簡単な 2 つのステップ:
(注: 何も変更する必要はありません - コピーして貼り付けるだけです)
1. create 関数

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;
于 2018-05-25T07:32:54.953 に答える
11

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
于 2011-04-20T01:56:42.443 に答える
6

これを集めた 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();すると、すべてのテーブルの行数が取得されます。

于 2010-04-15T13:25:43.513 に答える
5

すべてのテーブルを含めるように小さなバリエーションを作成し、非公開のテーブルも含めました。

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();して呼び出します。

これが役に立つことを願っています。ポール

于 2014-11-20T11:16:38.007 に答える