最大数のレコードをpostgresqlに保持することは可能ですか?


9

基本的に、Postgresqlテーブルの一部はサーバーアクセスログを保持するために使用されます。そのため、本番環境では、これがかなり大きくなる場合があります。postgresqlでテーブルが持つことができるレコードの最大数を設定し、最も古いレコードをプッシュする方法はありますか?

回答:


12

目的の行番号を維持するトリガーを定義できます。

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)。タイムスタンプ(または派生日付)を範囲分割の条件として使用できます。

ただし、古いログを破棄する前に注意してください。あなたはそれらを決して必要としないでしょうか?


定期的に実行することができ、テーブルがこれを必要とするほど大きくなれば、それらを必要としないと確信しています。DBメンテナンスをできるだけ自動化しようとしています:)
Jharwood

また、私はpostgresが自分自身のどちらが古いかを判断できることを期待していましたが、IDがないため、日付作成のタイムスタンプフィールド「2012-06-22 17:17:52.692514」を使用できます
Jharwood

@Jharwood-私の回答を編集しました。詳細が必要な場合は教えてください。
dezso

2
パーティション分割の提案で+1。毎回テーブルをスキャンするという極端なオーバーヘッドなしでカウントを実行したい場合は、pg_class.reltuplesを近似値として使用するか、トリガーを使用して「コントロール」テーブルのカウントを維持できます。
kgrittn 2012年

4

より一般的な、テーブルに依存しない関数を作成しました。

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つのパラメーターを取ります。

  • タブ:テーブル名
  • keyfld:数値、プログレッシブキーフィールド
  • nritems:保持するアイテムの数
  • rnd:0から1までの乱数。大きいほど、より頻繁にテーブルがクリーンアップされます(0 =しない、1 =常に、0.1 = 10%の回数)

このようにして、同じ関数を呼び出すトリガーの数を作成できます。

お役に立てれば。


0

私はこのプロシージャを作成し、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;
$$;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.