Est-il possible de conserver le nombre maximum d'enregistrements dans postgresql?

9

Fondamentalement, une partie de notre table Postgresql est utilisée pour conserver les journaux d'accès au serveur, et en tant que tel, parfois pendant la production, cela peut devenir assez volumineux. existe-t-il un moyen de définir dans postgresql pour avoir un nombre maximum d'enregistrements qu'une table peut avoir et pour repousser l'enregistrement le plus ancien?

Jharwood
la source

Réponses:

12

Vous pouvez définir un déclencheur pour conserver le numéro de ligne souhaité:

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();

Ce n'est probablement pas l'option la plus performante, mais une fois que vous atteignez la limite, elle ne sera jamais dépassée. S'il y a de la place pour les fluctuations, vous pouvez vérifier périodiquement le numéro de ligne et supprimer les lignes en excès depuis le début.

EDIT: Si vous avez de très gros journaux (disons un million par mois), le partitionnement peut être la solution la plus simple. Vous pouvez ensuite simplement supprimer les tables inutiles (dites oùmax(timestamp) < CURRENT_DATE - 1 year). Vous pouvez utiliser votre horodatage (ou une date dérivée) comme condition pour le partitionnement de la plage .

Mais soyez prudent avant de jeter les anciens journaux. Êtes-vous sûr que vous n'en aurez jamais besoin?

dezso
la source
nous pouvons l'exécuter périodiquement, et nous sommes sûrs que nous n'en aurons pas besoin une fois que la table sera suffisamment grande pour l'exiger, j'essaie simplement d'automatiser la maintenance de la base de données autant que possible :)
Jharwood
J'espérais également que les postgres pourraient dire lequel était le plus ancien lui-même, mais si nous n'avons pas d'identifiants, il pourrait utiliser notre champ d'horodatage créé "2012-06-22 17: 17: 52.692514"
Jharwood
@Jharwood - a modifié ma réponse. Veuillez me dire si vous avez besoin de plus de détails.
dezso
2
+1 sur la suggestion de partitionnement. Si vous voulez utiliser un décompte sans la surcharge extrême de l'analyse de la table à chaque fois, vous pouvez utiliser pg_class.reltuples pour une approximation ou vous pouvez utiliser des déclencheurs pour maintenir un décompte dans une table "de contrôle".
kgrittn
4

J'ai créé une fonction indépendante de la table plus générique.

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);

La fonction prend 4 paramètres:

  • onglet: nom de la table
  • keyfld: champ de touche numérique et progressif
  • nritems: nombre d'éléments à conserver
  • rnd: nombre aléatoire, de 0 à 1; plus elle est grande, plus la table sera nettoyée fréquemment (0 = jamais, 1 = toujours, 0,1 = 10% de fois)

De cette façon, vous pouvez créer le nombre de déclencheurs que vous souhaitez appeler la même fonction.

J'espère que cela t'aides.

Les bretelles
la source
0

J'ai créé ce proc et l'exécute à partir de PG Agent (ou du travail Windows ou du travail Cron en fonction). Je peux avoir plus de lignes, cela ne fait que garder ma table de journal pas trop grande. Enregistre les frais généraux d'un déclencheur.

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;
$$;

Ron H
la source