¿Es posible mantener el número máximo de registros en postgresql?

9

Básicamente, parte de nuestra tabla Postgresql se usa para mantener registros de acceso al servidor y, como tal, a veces durante la producción, esto puede ser bastante grande. ¿Hay alguna forma de establecer en postgresql para tener un número máximo de registros que una tabla puede tener y para eliminar el registro más antiguo?

Jharwood
fuente

Respuestas:

12

Puede definir un activador para mantener el número de fila deseado:

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

Probablemente esta no sea la mejor opción, pero una vez que llegue al límite, nunca se superará. Si hay espacio para la fluctuación, puede verificar el número de fila periódicamente y eliminar el exceso de filas desde el principio.

EDITAR: Si tiene registros realmente grandes (digamos un millón por mes), la partición puede ser la solución más fácil. Luego, simplemente puede soltar las tablas innecesarias (diga dóndemax(timestamp) < CURRENT_DATE - 1 year). Puede usar su marca de tiempo (o una fecha derivada) como condición para la partición de rango .

Pero tenga cuidado antes de desechar los registros antiguos. ¿Estás seguro de que nunca los necesitarás?

dezso
fuente
podemos ejecutarlo periódicamente, y estamos seguros de que no los necesitaremos una vez que la tabla sea lo suficientemente grande como para requerir esto, solo estoy tratando de automatizar el mantenimiento de la base de datos tanto como sea posible :)
Jharwood
También esperaba que Postgres supiera cuál era más antiguo, pero si no tenemos identificaciones, podría usar nuestro campo de marca de tiempo de fecha de creación "2012-06-22 17: 17: 52.692514"
Jharwood
@Jharwood - editó mi respuesta. Por favor dígame si necesita más detalles.
dezso
2
+1 en la sugerencia de partición. Si desea realizar un conteo sin la sobrecarga extrema de escanear la tabla cada vez, puede usar pg_class.reltuples para una aproximación o puede usar disparadores para mantener un conteo en una tabla de "control".
kgrittn
4

Creé una función de tabla independiente más genérica.

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 función toma 4 parámetros:

  • pestaña: nombre de la tabla
  • keyfld: campo numérico, clave progresiva
  • nritems: número de elementos para retener
  • rnd: número aleatorio, de 0 a 1; cuanto más grande sea, se limpiará la tabla más frecuente (0 = nunca, 1 = siempre, 0.1 = 10% de las veces)

De esta manera, puede crear cuántos disparadores desea llamar a la misma función.

Espero que esto ayude.

Correas
fuente
0

Creé este proceso y lo ejecuté desde PG Agent (o el trabajo de Windows o el trabajo cron dependiendo). Puedo tener más filas, esto solo mantiene mi tabla de registro no demasiado grande. Guarda la sobrecarga de un disparador.

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
fuente