回答:
この種のカウントを取得するには3つの方法があり、それぞれ独自のトレードオフがあります。
真のカウントが必要な場合は、各テーブルに対して使用したものと同様のSELECTステートメントを実行する必要があります。これは、PostgreSQLが行の可視性情報を他の場所ではなく行自体に保持するため、正確なカウントは特定のトランザクションにのみ関連するためです。そのトランザクションが実行された時点でそのトランザクションに表示されるものの数を取得しています。これを自動化してデータベース内のすべてのテーブルに対して実行することもできますが、おそらくそのレベルの精度は必要ないか、それほど長く待ちたくないでしょう。
2番目のアプローチは、統計コレクターがいつでも「ライブ」(削除されたり、後の更新によって廃止されたりしない)のおおよその行数を追跡することを示しています。この値は、負荷が高い状況では少しずれている可能性がありますが、概して適切な見積もりです。
SELECT schemaname,relname,n_live_tup
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
これは、死んだ行の数を示すこともできます。これは、それ自体が監視する興味深い数値です。
3番目の方法は、テーブルの統計情報を更新するためにPostgreSQL 8.3の時点でautovacuumプロセスによって定期的に実行されるシステム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の内部でも使用したい有用な情報があるかどうかに基づいてその決定を行います。基本的なカウントの目的では、全体の大きさを確認するためだけに、どちらも十分に正確である必要があります。
n_live_tup
か?私のRedshiftデータベースにはその列がありません。これはPostgres 8.0.2の派生物です。
pg_stat_user_tables
)クエリ(を使用)は、実行さn_live_tup
れたことANALYZE
がないため、ほとんどゼロを返しました。ANALYZE
すべてのスキーマ/テーブルで実行して回答を永遠に待つのではなく、最初に「第3のアプローチ」を使用して結果を確認し、その(pg_class
非常に正確な)カウントが返されました。
以下は、各テーブルの正確なカウントを取得するための関数を必要としないソリューションです。
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()
関数に渡す必要があります。
query_to_jsonb()
です。
select count(*)
すべてのテーブルで実行されています。
xpath()
関数は単一行にのみ適用されますcount(*)
見積もりを取得するには、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
、別の1 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億5000万行を超えるテーブルが存在する可能性があります(ただし、それらにcount(*)を実行することはお勧めできません)。
関数が複数の列を持つ結果セットを返すために、永続的な型を作成する必要はありません。RETURNS TABLE(definition...)
より良い代替手段です。
古くなっている可能性のあるデータを気にしない場合は、クエリオプティマイザーで使用されるのと同じ統計にアクセスできます。。
何かのようなもの:
SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
ANALYZE
テーブルでマニュアルを実行していない場合、統計が途切れる可能性があります。データベースの負荷とデータベースの構成方法に関する問題です(統計がより頻繁に更新される場合、統計はより正確になりますが、実行時のパフォーマンスが低下する可能性があります)。最終的に、正確なデータを取得する唯一の方法はselect count(*) from table
、すべてのテーブルに対して実行することです。
必要なHeroku計画を評価しようとしていて、herokuの低速な行カウンターが更新されるのを待つことができない人々に対する、ハッキーで実用的な答え:
基本的にはで実行\dt
したいのでpsql
、結果をお気に入りのテキストエディターにコピーします(次のようになります:
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
/g
(保持)し、最後にunion
セミコロン(;
)を1つ追加する必要があります。union
セミコロンの前の最後を削除することを忘れないでください。
union
セミコロンの前の最後を削除することを忘れないでください」が私が意味したものです:)明確にするために「最後」という単語を追加しました
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;
はOPで同じに要約されます!
特に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)
それ自体の関数に変換できるように見えるか、よりよく見えるはずです。
これを収集した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();
すると、すべてのテーブルの行数が表示されます。
quote_ident(t_name.relname)
は異なる名前(「column-name」など)が適切にサポートされるように、列名(など)を引用符で囲むことをお勧めします。
SELECT * FROM count_em_all() as r ORDER BY r.num_rows DESC;
簡単な2つのステップ:(
注:何も変更する必要はありません-コピーして貼り付けてください)
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;
すべてのテーブルを含めるための小さなバリエーションを作成しました。また、非パブリックテーブルについても同様です。
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();
それを呼び出すために使用します。
この情報がお役に立てば幸いです。ポール
これは私のために働いた
SELECT schemaname、relname、n_live_tup FROM pg_stat_user_tables ORDER BY n_live_tup DESC;
ダニエルベリテの答えが好きです。ただし、CREATEステートメントを使用できない場合は、bashソリューションを使用するか、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"
}
すべてのテーブルの合計+テーブルとそのカウントのリストが必要でした。ほとんどの時間が費やされた場所のパフォーマンスチャートのようなもの
WITH results AS (
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'
GROUP BY schemaname, relname, reltuples
)
SELECT * FROM results
UNION
SELECT 'all' AS schemaname, 'all' AS relname, SUM(reltuples) AS "reltuples" FROM results
ORDER BY reltuples DESC
もちろんLIMIT
、このバージョンの結果にも句を付けて、最大の結果を得ることができますn
て、合計だけでなく違反者。
これについて注意すべき1つの点は、一括インポート後にしばらく待機する必要があることです。実際のインポートデータを使用して、いくつかのテーブルにまたがるデータベースに5000行を追加するだけで、これをテストしました。約1分間に1800レコードを表示しました(おそらく構成可能なウィンドウ)
これはhttps://stackoverflow.com/a/2611745/1548557の作業に基づいているので、CTE内でクエリを使用することを感謝し、認識しています。
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;