回答:
目的の行番号を維持するトリガーを定義できます。
CREATE OR REPLACE FUNCTION trf_keep_row_number_steady()
RETURNS TRIGGER AS
$body$
BEGIN
-- delete only where are too many rows
IF (SELECT count(id) FROM log_table) > rownum_limit
THEN
-- I assume here that id is an auto-incremented value in log_table
DELETE FROM log_table
WHERE id = (SELECT min(id) FROM log_table);
END IF;
END;
$body$
LANGUAGE plpgsql;
CREATE TRIGGER tr_keep_row_number_steady
AFTER INSERT ON log_table
FOR EACH ROW EXECUTE PROCEDURE trf_keep_row_number_steady();
これはおそらく最高のパフォーマンスを発揮するオプションではありませんが、一度上限に達すると、それを超えることはありません。変動の余地がある場合は、定期的に行番号を確認し、余分な行を最初から削除できます。
編集:
本当に大きなログ(たとえば、月に100万回)がある場合は、パーティション分割が最も簡単な解決策になります。その後、不要なテーブルを削除できます(たとえば、と言いますmax(timestamp) < CURRENT_DATE - 1 year
)。タイムスタンプ(または派生日付)を範囲分割の条件として使用できます。
ただし、古いログを破棄する前に注意してください。あなたはそれらを決して必要としないでしょうか?
より一般的な、テーブルに依存しない関数を作成しました。
CREATE OR REPLACE FUNCTION keep_row_number_steady()
RETURNS TRIGGER AS
$body$
DECLARE
tab text;
keyfld text;
nritems INTEGER;
rnd DOUBLE PRECISION;
BEGIN
tab := TG_ARGV[0];
keyfld := TG_ARGV[1];
nritems := TG_ARGV[2];
rnd := TG_ARGV[3];
IF random() < rnd
THEN
EXECUTE(format('DELETE FROM %s WHERE %s < (SELECT %s FROM %s ORDER BY %s DESC LIMIT 1 OFFSET %s)', tab, keyfld, keyfld, tab, keyfld, nritems));
END IF;
RETURN NULL;
END;
$body$
LANGUAGE plpgsql;
CREATE TRIGGER log_table_keep_row_number_steady_trigger
AFTER INSERT ON log_table
FOR EACH STATEMENT EXECUTE PROCEDURE keep_row_number_steady('log_table', 'id', 1000, 0.1);
この関数は4つのパラメーターを取ります。
このようにして、同じ関数を呼び出すトリガーの数を作成できます。
お役に立てれば。
私はこのプロシージャを作成し、PGエージェント(またはWindowsジョブやcronジョブに応じて)から実行しました。より多くの行を含めることができます。これにより、ログテーブルが大きくなりすぎません。トリガーのオーバーヘッドを節約します。
CREATE or replace FUNCTION activitylogcleanup(_MaxRows int) RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
minid int;
BEGIN
SELECT logid into minid FROM activitylogapplication
order by logid desc limit 1 OFFSET _MaxRows;
if not found then
return;
END IF;
Delete from activitylogapplication where logid < minid;
END;
$$;