PostgreSQLを使っていて、「このデータベースの総レコード数って何件になる?」と聞かれることがたまにあります。
それはデータのサイズ感をデータディレクトリのサイズで言ってもピンとこなかったり、データ移行後に件数を比較するために正確な件数が知りたかったりと理由は様々あると思いますが、とにかくレコード数が知りたい。
手っ取り早く件数を調べるには以下のSQLが使えます。
SELECT reltuples FROM pg_class WHERE relname = '件数を調べたいテーブル名';
pg_classはPostgreSQLのシステムカタログ1の一つで、テーブルと、その他に列を持つもの、あるいはテーブルに似た全てのもの(インデックスやシーケンス等)の情報を格納しています。reltuples
列はテーブルのタプル数、つまりレコード数を保存しています。
しかしreltuples
の値はプランナが参照する推定値であり、正確ではありません。おおよその数を知るだけなら活用できますが、「正確な現在の件数」を調べるには不向きです。
正確な現在の件数を知るためには、COUNT関数を使用します。
SELECT COUNT(*) FROM 件数を調べたいテーブル名;
確かにCOUNT関数を使用すれば正確な件数がわかりますが、複数のテーブルの件数を同時に取得することができません。大量のテーブルがある場合、まずテーブルを列挙してSELECT COUNT(*)
をテーブルの数実行する必要があります。テーブルを列挙したときに漏れがあると困りますし、一個一個SQLを実行していくと時間もかかります。実行し忘れたりするかもしれません。
なんとか一発で全テーブルにもれなくSELECT文を実行できないか考え、PL/pgSQLで関数を作成することにしました。
CREATE OR REPLACE FUNCTION pg_temp.record_count()
RETURNS TABLE(objname TEXT, recordcount NUMERIC) AS $$
DECLARE
cursor_tablename CURSOR FOR
SELECT (schemaname || '.' || tablename) AS table_name
FROM pg_tables
WHERE
schemaname !~ 'pg_*' AND
schemaname != 'information_schema'
ORDER BY table_name;
BEGIN
FOR rec_table IN cursor_tablename LOOP
EXECUTE 'SELECT COUNT(*) FROM ' || rec_table.table_name INTO recordcount;
objname := rec_table.table_name;
RETURN NEXT;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
上記PL/pgSQLを実行し、次のSQLで作成した関数を実行すると、データベース内に存在する全てのテーブルとそのテーブルの件数がどばっと表示されます。ただし「pg_」から始まるスキーマに属するテーブルと「information_schema」に属するテーブルは除外しています。
SELECT * FROM pg_temp.record_count();
テーブル数やレコード数が多いと実行に結構時間がかかります。
なお、pg_tempスキーマに作成しているため、この関数はセッションが終了すると削除されます。
これは用が済んだあとに削除し忘れないようにしているためで、残しておいて時々使いたい場合はpublicに作成してもいいかもしれません。
-
リレーショナルデータベースがテーブルや列の情報などのスキーマメタデータと内部的な情報を格納する場所。 PostgreSQLのシステムカタログは通常のテーブルとして実装されている。 ↩