DBを使っている時、どのテーブルがどのくらい容量を食っているか知りたいことがあると思う。
また今後のサイズ増加を見積もりたいとき、あるテーブルの1行あたりの平均バイトサイズも知りたいはず!
PostgreSQLで見るべきところ
pg_classのテーブルの
- relpagesがブロック数
- reltuplesが行数
を表すらしい。
これらは実際にはプランナが用いる推測値。ANALYZEコマンドを打つとこれらの統計情報が更新されるので、ANALYZE直後にやるほうが正確。まぁ大抵、概算が知りたいだけなのであまり気にする必要ないかもしれないが。
ブロックサイズは8K(SHOW block_size;
で確認可能)なので
relpages / 128
Mbytesのサイズを占領しているということ。
平均サイズは、バイト数で知りたいのでrelpages * 8192 / reltuples
すれば良い。0割りが起こる可能性があるのでちゃんとやりたければCASE文を使えばいい気がするが、めんどくさい場合はめちゃくちゃ小さい値を分母に足したのでOK。
確認方法
上の議論を踏まえ、以下のクエリを発行する。
SELECT relname, reltuples, (relpages / 128) as mbytes, (relpages * 8192.0 / (reltuples + 1e-10)) as average_row_size FROM pg_class ORDER BY mbytes DESC;
こうすると、以下のようにテーブル名
、行数
、占有サイズ(Mbyte)
、平均サイズ(byte)
を占有サイズが大きい順に知ることができる。
relname | reltuples | mbytes | row_size
--------------------+-----------+--------+------------------
some_table | 89693 | 210 | 2456.75973866702
other_table | 93741 | 52 | 583.844509398135
....
なお、例えばユーザー情報をusers
テーブルに格納するとしたら、これののサイズはusers
テーブルのみじゃなく、それのIndexのサイズも加算しないといけないので注意。
Railsで作成した場合はusers_pkey
とかindex_users_on_hoge
みたいなテーブル名で存在しているはず。
より良いクエリ
上のクエリだとpg_toastなどが上に来ることがあり、原因がぱっとはつかめないことがある。
(参考: http://www.postgresql.jp/document/8.4/html/storage-toast.html )
そういう時は、以下のクエリを走らせると良い。
自分は、以下のPDFから拾った。詳細は知らないw
https://wiki.postgresql.org/images/a/ab/Pganalyze_Lightning_talk.pdf
SELECT pgn.nspname, relname, pg_size_pretty(relpages::bigint * 8 * 1024) AS size, CASE WHEN relkind =
't' THEN (SELECT pgd.relname FROM pg_class pgd WHERE pgd.reltoastrelid = pg.oid) WHEN nspname =
'pg_toast' AND relkind = 'i' THEN (SELECT pgt.relname FROM pg_class pgt WHERE SUBSTRING(pgt.relname
FROM 10) = REPLACE(SUBSTRING(pg.relname FROM 10), '_index', '')) ELSE (SELECT pgc.relname FROM
pg_class pgc WHERE pg.reltoastrelid = pgc.oid) END::varchar AS refrelname, CASE WHEN nspname =
'pg_toast' AND relkind = 'i' THEN (SELECT pgts.relname FROM pg_class pgts WHERE pgts.reltoastrelid =
(SELECT pgt.oid FROM pg_class pgt WHERE SUBSTRING(pgt.relname FROM 10) = REPLACE(SUBSTRING(pg.relname
FROM 10), '_index', ''))) END AS relidxrefrelname, relfilenode, relkind, reltuples::bigint, relpages
FROM pg_class pg, pg_namespace pgn WHERE pg.relnamespace = pgn.oid AND pgn.nspname NOT IN
('information_schema', 'pg_catalog') ORDER BY relpages DESC;
以下のようにサイズもGB, MBで表示してくれ、Index関係も何のIndexかも表示してくれる。
nspname | relname | size | refrelname | relidxrefrelname | relfilenode | relkind | reltuples | relpages
----------+----------------------+------------+----------------+------------------+-------------+---------+-----------+----------
pg_toast | pg_toast_16589 | 33 GB | some_table | | 33058906 | t | 17976238 | 4347405
pg_toast | pg_toast_16976 | 5963 MB | other_table | | 33059508 | t | 3088986 | 763266
public | another_table | 3681 MB | | | 33059230 | r | 85995424 | 471139
pg_toast | pg_toast_16589_index | 421 MB | pg_toast_16589 | some_table | 33058908 | i | 18334784 | 53837