Postgres のすべてのテーブルの行数を見つける方法を探しています。私はこれを一度に1つのテーブルで行うことができることを知っています:
SELECT count(*) FROM table_name;
しかし、すべてのテーブルの行数を確認し、それを並べ替えて、すべてのテーブルの大きさを把握したいと考えています。
Postgres のすべてのテーブルの行数を見つける方法を探しています。私はこれを一度に1つのテーブルで行うことができることを知っています:
SELECT count(*) FROM table_name;
しかし、すべてのテーブルの行数を確認し、それを並べ替えて、すべてのテーブルの大きさを把握したいと考えています。
この種のカウントを取得するには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内で使用したいより有用な情報があるかどうかに基づいてその決定を行います。基本的なカウントの目的で、一般的にどれだけ大きいかを確認するために、どちらも十分に正確である必要があります。
各テーブルの正確なカウントを取得するために関数を必要としないソリューションを次に示します。
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()
ます。
見積もりを取得するには、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...
ABCD
abcd
%I
information_schema.tables
table_type が'BASE TABLE'
(!) の場合でも、テーブルに加えてカスタム複合型を一覧表示します。結果として、 を繰り返すことはできません。そうしないと、失敗するinformation_schema.tables
リスクがあります。select count(*) from name_of_composite_type
OTOHpg_class where relkind='r'
は常に正常に動作するはずです。
COUNT() の型は でありbigint
、 ではありませんint
。21 億 5000 万行を超えるテーブルが存在する可能性があります (ただし、count(*) を実行することはお勧めできません)。
関数が複数の列を持つ結果セットを返すために、永続型を作成する必要はありません。RETURNS TABLE(definition...)
より良い代替手段です。
古いデータの可能性が気にならない場合は、クエリ オプティマイザーで使用されるのと同じ統計にアクセスできます。
何かのようなもの:
SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
簡単な 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;
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();
すると、すべてのテーブルの行数が取得されます。
すべてのテーブルを含めるように小さなバリエーションを作成し、非公開のテーブルも含めました。
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();
して呼び出します。
これが役に立つことを願っています。ポール