Ко-во if-ов уменьшается имея просто один параметр и логика становится сильно проще.
2)
Есть функция txid_visible_in_snapshot, что ещё больше упрощает понимаение.
3)
> ортить по паре (id, operation_type).
Это утверждение вообще говоря неправильное и приведёт к ошибкам. Видимо нужно сделать _id в таблице log и по ней сортить.
4)
Триггеры нормально работают с областью видимости в транзакции, а так же их действия откатываются.
Выходит, что всю это логику с видимостью можно впринципе убрать, так как, когда запускается синхронизатор, то он видит уже видимые закомиченные строки и может их потреблять в упорядоченном по _id.
Это правда?
Учитывая пункт 4, получается, что решение свелось к тому, что предложил Андрей выше с bigserial. Отличие в том, что у нас всё помещается в отдельный log и теперь пропущенные строки будут потребляться.
Мне кажется, что здесь должна быть где-то ошибка.
Приведу примерный sql фрагмент.
create table metrics (id bigserial primary key, device_id int, value int);
create table metrics_log (like metrics);
alter table metrics_log add column op_type text, add column _id bigserial primary key;
create or replace function tg_func_metrics_log () returns trigger as $xxx$
declare
rec record;
txid bigint;
begin
select txid_current() into txid;
IF TG_OP = 'INSERT' THEN
EXECUTE format('insert into %I select ($1).*, $$insert$$', TG_TABLE_NAME || '_log') using NEW;
RAISE NOTICE 'insert % % % %', NEW.id::text, NEW.xmin, NEW.xmax, txid;
rec = NEW;
END IF;
IF TG_OP = 'UPDATE' THEN
EXECUTE format('insert into %I select ($1).*, $$delete$$', TG_TABLE_NAME || '_log') using OLD;
EXECUTE format('insert into %I select ($1).*, $$insert$$', TG_TABLE_NAME || '_log') using NEW;
RAISE NOTICE 'delete % % % %', OLD.id::text, OLD.xmin, OLD.xmax, txid;
RAISE NOTICE 'insert % % % %', NEW.id::text, NEW.xmin, NEW.xmax, txid;
rec = NEW;
END IF;
IF TG_OP = 'DELETE' THEN
EXECUTE format('insert into %I select ($1).*, $$delete$$', TG_TABLE_NAME || '_log') using OLD;
RAISE NOTICE 'delete % % % %', OLD.id::text, OLD.xmin, OLD.xmax, txid;
rec = OLD;
END IF;
return rec;
end;
$xxx$ language plpgsql;
create trigger trigger_metrics_log
after insert or update or delete on metrics
for each row execute procedure tg_func_metrics_log();
insert into metrics (device_id, value) values (1, 1);
update metrics set value = 2 where id = 1;
delete from metrics;
Здесь нету sql кода синхронизатора. Поидее он должен брать какие-то строки из log и удалять их после потребления. Работать должен минимум в repeatable read.
Само потребление можно сделать, как выгрузку в csv файл или в таблицу для простоты.
> Здесь нету sql кода синхронизатора. Поидее он должен брать какие-то строки из log и удалять их после потребления. Если так, зачем тут вообще XID-ы? Почему бы просто не логировать все операции, как у Вас, а потом не удалять при потреблении? Т.е. WITH d AS (DELETE FROM metrics_log RETURNING *) INSERT INTO target(...) SELECT ... FROM d;
Обсуждают сегодня