LINUX.ORG.RU

Ротация записей в бд

 , ,


2

1

С бд работал мало, но появилась задача. Запилить логгирование в бд с ротацией данных (удаление старых записей, чтобы их кол-во не превышало какой-то определенный размер, который кстати можно менять). Хотелось бы обсудить с опытными скуэльщиками, как правильно это реализовать. Делать подсчет и при необходимости удалять при _каждом_ инсерте мне кажется неразумно. Какие идеи?

★★★★★

logstash + elastic + kibana.

1) Быстрая запись в лог, не надо грузить базу 2) Человечный поиск по неструктурированным данным 3) Человечная морда, которую не надо писать самому

anonymous
()
Ответ на: комментарий от Rastafarra

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

сейчас сделано на check constraints со всеми вытекающими (при изменении макс размера приходится отбрасывать ограничение, создавать новые, ловить возможно исключение и тд).

vvviperrr ★★★★★
() автор топика
Последнее исправление: vvviperrr (всего исправлений: 2)
Ответ на: комментарий от vvviperrr

как определять, что таблица заполнена и нужно ротировать?

тебе прям в штуках? ну хз, count вроде не шибко быстр, вроде можно было селектить из системных постргесовых таблиц.

быстрогугл: http://stackoverflow.com/questions/7943233/fast-way-to-discover-the-row-count...

как поддержать изменение максимального размера?

я вот даже не понял вопроса. изменить правило? можно сделать таблицу settings: code, value и селектить по коду log_max_size, если ты хочешь что-то типа админки этой радостью.

Rastafarra ★★★★
()
Ответ на: комментарий от Rastafarra

ну хз, count вроде не шибко быстр, вроде можно было селектить из системных постргесовых таблиц.

ты предлагаешь при каждом insert делать count либо select из системной таблицы? при КАЖДОМ insert?

vvviperrr ★★★★★
() автор топика
Ответ на: комментарий от vvviperrr

при КАЖДОМ insert?

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

Rastafarra ★★★★
()

Да просто повесь хранимку в запуск по расписанию и пусть она чистит.

Deleted
()

А не проще настроить партицироование таблицы логов ?

Balantay
()

Подсчёт делать придётся по-любому :-) А удалять можно все записи из таблицы логов скопом при превышении лимита :-) На коленке написал специально для тебя :-) Решение не годится, если избирательно удалять записи из log вручную :-) Можно только delete from log :-) (оптимизация) :-) Ну и схема не учитывается, только имя таблицы :-)

begin;
-- test tables
-- 2 таблицы - row_counter со счетчиком записями в таблицах и log с логами.
drop table if exists row_counter;
drop table if exists log;
create table log(id serial not null primary key, info text);
create table row_counter(tab regclass not null primary key, counter bigint not null);
insert into row_counter select 'log', count(*) from log;

-- triggers
create or replace function row_counter_incr () returns trigger language plpgsql  as $$
begin
update row_counter set counter = counter + 1 where tab = 'log'::regclass;
return new;
end;
$$;

create trigger trigger1
before insert on log for each row execute procedure row_counter_incr();

create or replace function row_counter_decr () returns trigger language plpgsql  as $$
begin
update row_counter set counter = 1;
return null;
end;
$$;

create trigger trigger2
after delete on log for each row execute procedure row_counter_decr();

create or replace function log_cleaner () returns trigger language plpgsql as $$
declare
  lim constant integer := TG_ARGV[0];
begin
if (select counter > lim from row_counter where tab = 'log'::regclass) then
  delete from log;
end if;
return new;
end;
$$;

-- пусть логов будет не больше 1000
create trigger trigger3
before insert on log for each row execute procedure log_cleaner(1000);

commit;

-- test
--insert into log(info) select 'info' from generate_series(1,2000);
-- INSERT 0 2000
-- Time: 473,725 ms

-- select * from row_counter;
--  tab | counter
-- -----+---------
--  log |    1000
-- (1 row)

-- select count(*) from log;
--  count
-- -------
--   1000
-- (1 row)

anonymous
()
Ответ на: комментарий от anonymous

Ну и схема не учитывается, только имя таблицы :-)

А, не, учитывается :-)

anonymous
()

Я бы попробовал upsert (insert... on duplicate key update) + pk_id = table_sequence.next() % max_rows

cobold ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.