Можно ли сохранить максимальное количество записей в postgresql?

9

В основном часть нашей таблицы Postgresql используется для хранения журналов доступа к серверу, и поэтому иногда в процессе производства она может быть довольно большой. Есть ли способ установить в postgresql максимальное количество записей, которое может иметь таблица, и отодвинуть самую старую запись?

Jharwood
источник

Ответы:

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

Это, вероятно, не самый эффективный вариант, но как только вы достигнете предела, он никогда не будет превышен. Если есть место для колебаний, вы можете периодически проверять номер строки и удалять лишние строки с самого начала.

РЕДАКТИРОВАТЬ: Если у вас действительно большие журналы (скажем, миллион в месяц), то разделение может быть самым простым решением. Затем вы можете просто удалить ненужные таблицы (скажем, гдеmax(timestamp) < CURRENT_DATE - 1 year). Вы можете использовать свою временную метку (или производную дату) в качестве условия для разделения диапазона .

Но будьте осторожны, перед тем как выбросить старые журналы. Вы уверены, что они вам никогда не понадобятся?

Dezso
источник
мы можем выполнять его периодически, и мы уверены, что они нам не понадобятся, когда таблица станет достаточно большой, чтобы требовать этого, я просто пытаюсь максимально автоматизировать обслуживание БД :)
Jharwood
Также я надеялся, что postgres сможет сказать, какой из них сам старше, но если нет, поскольку у нас нет идентификаторов, он может использовать поле даты и времени, созданное датой "2012-06-22 17: 17: 52.692514"
Jharwood
@Jharwood - отредактировал мой ответ. Пожалуйста, скажите мне, если вам нужна дополнительная информация.
Дезсо
2
+1 за предложение о разделении. Если вы хотите использовать счетчик без лишних затрат на сканирование таблицы каждый раз, вы можете использовать pg_class.reltuples для приблизительной оценки, или вы можете использовать триггеры для поддержания счетчика в «контрольной» таблице.
кгритт
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 Agent (или в зависимости от заданий 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;
$$;
Рон Х
источник