powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / plpgsql и триггеры
14 сообщений из 14, страница 1 из 1
plpgsql и триггеры
    #32488797
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Есть таблицы:
CREATE TABLE tr_email
(
id serial,
category_id int not null,
address varchar(255) not null,
is_active bool not null default true,

primary key(id)
);

CREATE TABLE tr_category_stats
(
id serial,
category_id int not null,
total int4 not null default 0,
removed int4 not null default 0,
updated timestamp not null default now(),

primary key(id)
);

и триггер:
CREATE TRIGGER tr_update_stats AFTER INSERT OR UPDATE OR DELETE ON tr_email FOR EACH STATEMENT EXECUTE PROCEDURE update_stats();

В функции update_stats() нужно обновить информацию в таблице tr_category_stats. Проблема в том что триггер вызывается FOR EACH STATEMENT и доступа к данным (NEW и OLD) НЕТ. И сделать такое:

SELECT INTO total_cnt count(*) FROM tr_email WHERE category_id = NEW.category_id;
SELECT INTO removed_cnt count(*) FROM tr_email WHERE category_id = NEW.category_id AND is_active = ''false'';
UPDATE tr_email_category_stats SET total = total_cnt, removed = removed_cnt, updated = now() WHERE category_id = NEW.category_id;
RETURN NEW;

НЕЛЬЗЯ.

category_id один для всего обновляемого набора. Нельзя ли его как-нибудь получить в триггере?

Возможно есть другие варианты решения проблемы?
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32491008
centur
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
про category_id Afaik нельзя.
А что мешает вызывать for each row - актуализация второй таблицы будет "мгновенной" и точной.
к тому же оцените как часто будет этот триггер срабатывать и на сколько записей сразу и прикиньте -а стоит ли each statement неудобств отсутствия кортежей NEW OLD


немного оффтопика
А с какой версии работает конструкция выделенная болдом, может я что-то пропустил ?
CREATE TRIGGER tr_update_stats AFTER INSERT OR UPDATE OR DELETE ON tr_email FOR EACH STATEMENT EXECUTE PROCEDURE update_stats();
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32491063
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Дело в том что функция, которая висит на триггере (update_stats()), выполняет 2 раза count() для таблицы, объём которой будет порядка 100 млн. записей.
Так вот мне кажется что если триггер повесить на FOR EACH ROW, то время операции значительно увеличится. (Насколько я знаю count() при таких объёмах работает не очень быстро).

А на счёт конструкции: это версия 7.4.2, просто я раньше с PostgreSQL не работал - поэтому не совсем понял ваше сомнение.
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32491435
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
наверное можно так:

на ROW закопляйте NOW.id куда-нить (подошли бы временные таблички, но тут с ними некий гемор), а на STATEMENT вшурупливайте их (id) по месту.

Т.е. в порядной обработке не вызывайте COUNT() и т.п. тормоза, но закопляйте необходимые вам в последующем данные.
( Temporary tables are automatically dropped at the end of a session, or optionally at the end of the current transaction (see ON COMMIT)).


Надеюсь, доны застарелые слонолюбы дадут вам более полезные советы.


/я как-то подумывал создавать свои #inserted и #deleted таким макаром, но тогда все, что касается этих "внутрисеансных табличек" должно выглядеть как динамический сыккуль - "EXECUTE \'...\'", не уверен, что не будет межсеансных проблем, хотя хелп по TEMPORARY/TEMP позволяет на это надеяться - но пока обошелся тем, что попроще (порядной обработкой) - ибо данных пока немного/)/

PS. А зачем вы 2 раза считаете один и тот же count()? может таки достаточно посчитать 1 раз :).
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32493038
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
assaPS. А зачем вы 2 раза считаете один и тот же count()? может таки достаточно посчитать 1 раз :).

1-ый раз: количество всех записей
2-ой раз: количество неактивных

А нельзя ли как-нибудь в триггере на ROW запоминать category_id не во временную табличку, а в какую-нибудь переменную. А потом её использовать в триггере на STATMENT?
Этот id`ик ведь будет один для всего набора записей. Если можно, то подскажите как это сделать. Я чего-то ума не приложу.
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32493453
assa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ok, заметил AND is_active = ''false''; (хотя не понял, почему "false" а не false, ну да ладно).

по поводу переменной ничего не скажу. Если имеются в виду переменные pgsql, то их область видимости - процедура, в которой они описаны. Т.ч. они вам не подходят (у вас одна процедура - ф-я триггера, вызываемая к примеру before ... для каждого ряда, а вторая - ф-я триггера, вызываемая after ... - для стейтмента). Т.е. вам придется передаваться через переменные описанные в каких-то других языках (и возвращаемые функциями написанными на этих других языках). Если же вы хотите остаться в пределах SQL/pgsql, придется передаваться через объекты б.д., т.е., насколько я понимаю, через таблицы или счетчики. При этом, поскольку вряд ли вам нужны проблемы с сетевой или многосеансной работой, вам нужны объекты, существующие в отдельном сеансе и невидимые из других (могущие иметь одноименные независимые "копии" в других сеансах). А это Temporary таблицы/счетчики.


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

ЗЫ: кстати, что такое NEW в AFTER ... DELETE ? (там ведь будет OLD)
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32493990
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
assaкстати, что такое NEW в AFTER ... DELETE? (там ведь будет OLD)

Да, там действительно будет OLD. Просто в этой процедуре обрабатывались все 3 случая (INSERT, UPDATE, DELETE), а я вставил сюда лишь для INSERT.

Спасибо за совет!!! хоть кто-то что-то сказал по существу................
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32504235
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По-моему, здесь очень хорошо подойдут триггеры FOR EACH ROW.
aev
(Насколько я знаю count() при таких объёмах работает не очень быстро).

Никаких каунтов делать не нужно.
В триггере FOR EACH ROW:
Если запись вставляется, то update tr_category_stats set total = total +1; (или вставка новой записи с total=1)
Если запись удаляется, то смотрим на is_active и уменьшаем на единицу соотв. количество.
Если запись обновляется, то смотрим на изменение флага is_active и выполняем уменьшение/увеличение total/removed.


Если в таблице tr_email предполагаются массовые удаления/обновления, то можно (как пример) добавить дополнительную таблицу, в которой будет изменяться флаг перед такими массовыми операциями. А в триггере проверять этот флаг и если установлен, то ничего не делать.
И массовые удаления/обновления выполнять отдельной процедурой, без всяких триггеров.
То есть, схема процедуры примерно следующая:
1. Блокируем таблицу tr_email
2. Выставляем флаг, что начали массовую обработку.
3. Копируем во временную таблицу рабочую выборку из category_id и и количества. (То есть, если операция update tr_email set is_active=false where category_id in (2, 3, 6) and is_active=true, то выбираем предикат и вставляем во временную таблицу такое: select category_id, count(*) from tr_email where category_id in (2, 3, 6) and is_active=true group by category_id. Если некоторые записи из одной категории могут быть is_active=true, а другие is_active=false, то все усложняется...)
4. Делаем чего хотели (удаляем или обновляем).
5. Для каждой строки из временной таблицы делаем правильный update tr_category_stats.
6. Сбрасываем флаг.

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

Жаль, триггер нельзя задизэйблить, или я еще не знаю чего-то...

В общем-то, можно и на Statement-триггерах делать, наверно, но надо все еще раз хорошо оценить. Для обеспечения согласованности в этом случае, наверно, придется использовать уровень изоляции serializable.
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32504623
аха
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
2 Заглянул

а теперь докажите, что 100 апдейтов (пусть без подсчета каунта), лучше 1 апдейта с подсчетом :0).

Или что изгиляться с недотыкомками полезней, чем пользоваться готовыми продуманными решениями
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32508236
centur
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
немного оффтопа - задисэйблить триггера можно но либо все (reltriggers =0 , умрут также все констрейнты и ключи, у нас таким образом накосячили в базе и нарушили целостность, когда записей нету а foreign key с рестрикт делитом лежит и не чешется... =( )

либо по имени таблицы находить все триггера в системных и перевешивать на другой оид\таблицу..
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32508777
офтоп
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ок. А во время подъема дампа чо происходит? (я сам не поднимаю, но видел пару раз, что триггера не отрабатывают (в процессе заливки). оно может и к лучшему - а то неподьемно ж на каждую запись пересчитывать итоги, но пришлось писать процедурку для заполнения промежуточных итогов и прочей лабуды после таких операций. Такоже апдейтить счетчики под максимум после заливки). Или это от параметров pg_restore зависит?
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32508828
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 centur: Это путь для смелых и продвинутых людей. ;-) Я в таблицах словаря предпочитаю не ковыряться, боюсь. ;)

2 аха:

Так кто ж спорит, можит и не лучше, а может даже намного хуже. Может, каунт у вас будет почти моментальным. ;)
Просто надо протестировать на конкурирующих транзакциях, чтобы убедиться, что в результате итоговые значения будут корректными. А можно проверить разные подходы и сравнить.

З.Ы.
аха
Или что изгиляться с недотыкомками полезней, чем пользоваться готовыми продуманными решениями
Эту фразу я понять не могу. ;-) О чем это вы?
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32509903
centur
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну у меня ручки шаловливые - лазим всюду

2офтоп - ну правильно, это и делается, триггера и ключи отключаются для увеличения скорости
...
Рейтинг: 0 / 0
plpgsql и триггеры
    #32511181
Заглянул
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 aev & аха: (вдогонку)

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


Удачи.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / plpgsql и триггеры
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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