powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Триггер AFTER с получением списка измененных строк (версия < 10)
11 сообщений из 11, страница 1 из 1
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780155
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имею задачу которую в общем виде можно описать так:
- Клиенты выгребают из таблицы строки которые изменились с определенного момента
- Признак что строка изменилась является поле типа timestamp (time_change)
- Есть отдельная таблица которая хранит время до какого момента клиент уже получил измененные данные
- Строки изменяются в транзакции, которая может длится достаточно долго (пусть 5 минут на изменение многих таблиц)
- В транзакции срабатывает триггер на установку момента изменения строки
- Возникают ситуации когда транзакция изменяющая данные уже идет, клиент подключился, посмотрел, что для него данных нет, записал в таблицу время когда проверял наличие новых данных и отключился. В это время закончилась транзакция которая обновляла данные и закоммитилось время раньше чем клиент проверял.
- При таком раскладе гарантированно клиент не получает часть обновленных данных

Начал делать примерно следующее

pg_dump
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
--
-- PostgreSQL database dump
--


CREATE FUNCTION public.return_time_change() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN

UPDATE xtime AS t
SET    time_change = clock_timestamp(), updated = false
WHERE  t.id = NEW.id;

  return null;
END;
$$;


CREATE FUNCTION public.return_time_create() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
BEGIN
  
UPDATE xtime AS t
SET    time_create = clock_timestamp(), time_change = clock_timestamp()
WHERE  t.id = NEW.id;

return null;
END;
$$;


CREATE TABLE public.xtime (
    id bigint NOT NULL,
    a text,
    time_create timestamp with time zone,
    time_change timestamp with time zone,
    updated boolean DEFAULT true
);


CREATE SEQUENCE public.xtime_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.xtime_id_seq OWNED BY public.xtime.id;


ALTER TABLE ONLY public.xtime ALTER COLUMN id SET DEFAULT nextval('public.xtime_id_seq'::regclass);

ALTER TABLE ONLY public.xtime ADD CONSTRAINT xtime_pkey PRIMARY KEY (id);


CREATE CONSTRAINT TRIGGER time_change AFTER UPDATE ON public.xtime DEFERRABLE INITIALLY DEFERRED FOR EACH ROW WHEN (new.updated) EXECUTE PROCEDURE public.return_time_change();
CREATE CONSTRAINT TRIGGER time_create AFTER INSERT ON public.xtime DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE public.return_time_create();




Тестирую так:
Код: plsql
1.
2.
3.
begin;
insert into xtime (a) SELECT generate_series(1,400000)::text;
commit;



Да, триггер выполняется один раз (в том числе благодаря костылю updated, но с этим можно смириться).
Только time_change измененных строк после коммита имеет разницу в несколько секунд, что есть проблема.

Есть ли способ для версий ниже 10 получить в процедуре готовый список строк и установить им time_change одним запросом чтобы время у всех строк было одинаковое и равнялось моменту коммита?

Возможно есть какой-то более правильный способ делать то, что я хочу не изобретая велосипед?
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780206
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YP977,

imho всё неправильно.

вам нужна отдельная таблица/запись "по какой момент (номер транзакции) клиент имеет право читать". == "с какого момента (номера транзакции) джобы имеют право читать".

использование клок-таймстампа вместо каррента неоправдано почти никогда.
да и вообще замыкаться на время -- не правильно. (время сервера иногда меняется). вернее пользоваться ид-транзакций(TXID) и видимостями (SNAPSHOT). https://www.postgresql.org/docs/10/functions-info.html#FUNCTIONS-TXID-SNAPSHOT

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

на крайняк пользуйтесь pgq -- там всё готово
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780332
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
qwwq,

О, как-то не думал об этом. Спасибо покопаю в эту сторону.
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780584
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
qwwq,

Еще раз спасибо!!

Разобрался с TXID, почитал документацию и проникся. Понял, что работа с временем - это очень кривое решение, велосипед еще тот :)

В целом сейчас выборка нужных мне записей свелась к запросу

Код: plsql
1.
select * from xtime where xmin::text::bigint > 374376899;



А номер транзакции получаю через txid_current();

Поиграюсь с большими таблицами и большими выборками, но не думаю, что это будет медленные чем выборка по индексированному timestamp.
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780599
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YP977,

не забудьте проверить работу при wraparound.
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780637
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Спасибо за подсказку.
Проверю.
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780660
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
В документации версии 9.6 написано следующее

Внутренний тип идентификаторов транзакций (xid) имеет размер 32 бита, поэтому они повторяются через 4 миллиарда транзакций. Однако эти функции выдают 64-битные значения, дополненные счётчиком «эпохи», так что эти значения останутся уникальными на протяжении всей жизни сервера.

64 бита точно хватит

Но что-то закрались сомнения.
Посмотрел на сервера которые достаточно старые и там значения txid_current() какие-то маленькие...
479 903 869
375 192 752
523 133 340

Это у меня сервера не нагруженные или что-то не так с документацией?

Какие у вас выдаются значения? Есть больше 4 294 967 296?
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780668
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YP977,

Самое интересное будет когда вы во время апгрейда сделаете дамп базы и загрузите его в новую версию.
И, внезапно, txid_current() будет возвращать значения меньше, чем те, что у вас в таблицах зафиксированы.

Это похоже на эффект от wraparound.

Завязываясь на системные колонки базы вы вступаете на путь удивительных открытий!
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780669
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,

Да это так.
Логика работы приложения в целом позволяет такому случиться.
Это не будет приятно, но не смертельно.

Все равно пока лучшего решения у меня нет...
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39780685
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vyegorovYP977,

Самое интересное будет когда вы во время апгрейда сделаете дамп базы и загрузите его в новую версию.
И, внезапно, txid_current() будет возвращать значения меньше, чем те, что у вас в таблицах зафиксированы.

Это похоже на эффект от wraparound.

Завязываясь на системные колонки базы вы вступаете на путь удивительных открытий!
это лечится выставлением эпохи кластера.
подробности лень искать. (про перенос пгку)
неудобство -- требует останова.
если не знать -- можно сильно побиться при переезде
...
Рейтинг: 0 / 0
Триггер AFTER с получением списка измененных строк (версия < 10)
    #39781101
YP977
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
На всякий случай.
Я нашел таки сервер у которого txid_current() больше чем 2^32

Конкретное значение = 4 578 378 203

Так что можно спать спокойно. Если не переносить базу на другой сервер/кластер все будет ок.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Триггер AFTER с получением списка измененных строк (версия < 10)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]