ディスク クォータを使用すると、非常に多くの作業が必要になります。実際、PostgreSQL にはおおよその解決策があり、いくつかのマイナーな変更があり、多数のテーブルスペースを作成する必要はありません (すべてのユーザーに独自の名前空間を与えるには、スキーマを使用することをお勧めします)。
この関数pg_total_relation_size(regclass)
は、インデックスと TOAST テーブルを含む、テーブルに使用されるディスク容量の合計を示します。したがって、スキャンpg_class
して要約します。
CREATE VIEW user_disk_usage AS
SELECT r.rolname, SUM(pg_total_relation_size(c.oid)) AS total_disk_usage
FROM pg_class c, pg_roles r
WHERE c.relkind = 'r'
AND c.relowner = r.oid
GROUP BY c.relowner;
これにより、テーブルの場所に関係なく、各所有者が使用するディスク容量の合計がわかります。以下で使用するために、ここではビュー定義として提示されています。
これを適度に正確に機能させるにはVACUUM ANALYZE
、データベースを定期的に更新する必要があります。トラフィックの少ない時間帯 (たとえば、毎日午前 3 時から午前 5 時、または日曜日) に実行してから、ユーザー postgres でスケジュールされたジョブを使用します。VACUUM を実行してからクォータ チェックを実行するジョブの関数を作成します。
CREATE FUNCTION user_quota_check() RETURNS void AS $$
DECLARE
user_data record;
BEGIN
-- Vacuum the database to get accurate disk use data
VACUUM FULL ANALYZE;
-- Find users over disk quota
FOR user_data IN SELECT * FROM user_disk_usage LOOP
IF (user_data.total_disk_usage > <<your quota>>) THEN
EXECUTE 'REVOKE CREATE ON SCHEMA ' || <<user''s schema name>> || ', PUBLIC FROM ' || user_data.rolname;
-- REVOKE INSERT privileges too, unless you work with BEFORE INSERT triggers on all tables
END IF;
END LOOP;
END; $$ LANGUAGE plpgsql;
REVOKE ALL ON FUNCTION user_quota_check() FROM PUBLIC;
所有者が割り当てを超えた場合、REVOKE CREATE
関連するすべてのスキーマ (通常は、ユーザーに割り当てられたスキーマとパブリック スキーマのみ) で、新しいテーブルを作成できなくなります。すべてのテーブルでも行う必要がありますREVOKE INSERT
が、所有者はすぐに戻ることができるため、これは簡単に回避できGRANT INSERT
ます。ただし、これは、ユーザーに対するより抜本的なアクションの原因になる可能性があります。上記のような毎日のスイープを使用して、データベース内のすべてのテーブルに挿入前トリガーを作成することをお勧めします。
ユーザーは引き続き SELECT 権限を持っているため、引き続きデータにアクセスできます。さらに興味深いことに、DELETE と TRUNCATE を使用すると、ユーザーはディスク領域を解放し、ロックアウトを修正できます。その後、上記の関数に似たものを使用して権限を回復できます。
CREATE FUNCTION reclaim_disk_space() RETURNS void AS $$
DECLARE
disk_use bigint;
BEGIN
-- Vacuum current_user's tables.
-- Slow and therefore adequate punishment for going over quota.
VACUUM FULL VERBOSE ANALYZE;
-- Now re-instate privileges if enough space was reclaimed.
SELECT total_disk_usage INTO disk_use
FROM user_disk_usage
WHERE rolname = session_user;
IF (disk_use < <<your quota>>) THEN
EXECUTE 'GRANT CREATE ON SCHEMA ' || <<user''s schema name>> || ', PUBLIC TO ' || user_data.rolname;
-- GRANT INSERT privileges too, unless you work with BEFORE INSERT triggers on all tables
RAISE NOTICE 'Disk use under quota limit. Privileges restored.';
ELSE
RAISE NOTICE 'Still using too much disk space. Free up more space.';
END IF;
END; $$ LANGUAGE plpgsql;
ロックアウトされたユーザーは、クォータ制限を下回るのに十分なデータを削除した後、この関数を自分で呼び出すことができます。
(全体のクォータではなく) ユーザーごとのクォータを一覧表示するテーブルを作成し、実際の使用量をそのクォータと比較したり、RAISE NOTICE
クォータの 80% を超えたときに挿入トリガーを発行したりするなど、より高度な機能を追加できます (これには、すべてのテーブルで新しいテーブルの定期的なスイープで postgres ユーザーが簡単に実行できる before insert トリガーがあり、クォータを超えた場合は同じトリガーを使用して挿入を拒否できます)、その通知を 1 時間ごとに繰り返します (最後の通知がいつ発行されたかを記録します) )など
クォータはリアルタイムでチェックされないため、このソリューションは概算です。これは可能です (すべての挿入で user_quota_check() を実行し、session_user のテーブルのみをチェックするように変更します) が、興味を引くにはオーバーヘッドが多すぎる可能性があります。クォータを毎日管理するには、user_quota_check() を一晩実行します。そして、日中にあまりにも多くのスペースを使用しているユーザーを手動で非難します。