Possibile mantenere il numero massimo di record in Postgresql?


9

Fondamentalmente una parte della nostra tabella Postgresql viene utilizzata per conservare i registri di accesso al server e come tale a volte durante la produzione può diventare piuttosto grande. c'è un modo per impostare in postgresql di avere un numero massimo di record che una tabella può avere e di cancellare il record più vecchio?

Risposte:


12

È possibile definire un trigger per mantenere il numero di riga desiderato:

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

Questa probabilmente non è l'opzione con le migliori prestazioni, ma una volta raggiunto il limite, non sarà mai superata. Se c'è spazio per le fluttuazioni, è possibile controllare periodicamente il numero di riga ed eliminare le righe in eccesso dall'inizio.

EDIT: se hai registri molto grandi (diciamo un milione al mese), il partizionamento può essere la soluzione più semplice. È quindi possibile semplicemente eliminare le tabelle non necessarie (dire dovemax(timestamp) < CURRENT_DATE - 1 year). È possibile utilizzare il timestamp (o una data derivata) come condizione per il partizionamento dell'intervallo .

Ma fai attenzione prima di scartare i vecchi registri. Sei sicuro di non averne mai bisogno?


possiamo eseguirlo periodicamente e siamo sicuri che non avremo bisogno di loro una volta che la tabella sarà abbastanza grande per richiederlo, sto solo cercando di automatizzare il più possibile la manutenzione del DB :)
Jharwood,

speravo anche che Postgres potesse dire quale era più vecchio, ma se non avessimo i documenti d'identità potrebbe usare il nostro campo data e ora creato "22/06/2012 17: 17: 52.692514"
Jharwood,

@Jharwood - ha modificato la mia risposta. Per favore dimmi se hai bisogno di ulteriori dettagli.
dezso

2
+1 sul suggerimento di partizionamento. Se si desidera procedere con un conteggio senza il sovraccarico estremo di scansionare la tabella ogni volta, è possibile utilizzare pg_class.reltuples per un approssimativo o è possibile utilizzare i trigger per mantenere un conteggio in una tabella "controllo".
kgrittn,

4

Ho creato una funzione più generica, indipendente dalla tabella.

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 funzione accetta 4 parametri:

  • scheda: nome della tabella
  • keyfld: campo chiave numerico progressivo
  • nritems: numero di elementi da conservare
  • rnd: numero casuale, da 0 a 1; più è grande, più verrà pulita la tabella frequente (0 = mai, 1 = sempre, 0,1 = 10% delle volte)

In questo modo è possibile creare quanti trigger si desidera chiamare la stessa funzione.

Spero che sia di aiuto.


0

Ho creato questo proc ed eseguito da PG Agent (o lavoro di Windows o cron a seconda). Posso avere più righe, questo mantiene la mia tabella di registro non troppo grande. Salva l'overhead di un trigger.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.