Возможно ли это корректно сделать?
-
- Сообщения: 4
- Зарегистрирован: 11 сен 2010, 17:31
Возможно ли это корректно сделать?
Есть две таблицы
create table A (ida integer, maxdate date)
create table B (idb integer, ida integer, dateb date)
В таблице B может быть произвольное число записей с одинаковым ida. Возможно ли на тригерах так организовать обновление поля maxdate, чтобы оно всегда было равно (select max(dateb) from B where B.ida=A.ida) ?
Firebird 1.5.
create table A (ida integer, maxdate date)
create table B (idb integer, ida integer, dateb date)
В таблице B может быть произвольное число записей с одинаковым ida. Возможно ли на тригерах так организовать обновление поля maxdate, чтобы оно всегда было равно (select max(dateb) from B where B.ida=A.ida) ?
Firebird 1.5.
Re: Возможно ли это корректно сделать?
триггеры работатют только в контексте пользовательских транзакций, так что при определенных условиях на целостность данных, обновляемых таким образом, расчитывать не стоит.
Кроме того, как я понимаю, связь b к a это "много к одной", а значит если несколько пользователей обновят B, то они могут столкнуться по конфликту обновления (триггером) одной и той же записи в A.
Насчет, "возможно ли это корректно сделать" - неясен вопрос. Написать такой триггер можно без проблем. Вы пробовали?
Кроме того, как я понимаю, связь b к a это "много к одной", а значит если несколько пользователей обновят B, то они могут столкнуться по конфликту обновления (триггером) одной и той же записи в A.
Насчет, "возможно ли это корректно сделать" - неясен вопрос. Написать такой триггер можно без проблем. Вы пробовали?
-
- Сообщения: 4
- Зарегистрирован: 11 сен 2010, 17:31
Re: Возможно ли это корректно сделать?
kdv, вопрос как раз в том, как обеспечить целостность данных.
Обеспечит ли такой триггер целостность при условии, что все обновления будут запускаться в транзакциях с параметрами read_committed nowait ?
Код: Выделить всё
CREATE OR ALTER trigger b_aiud0 for b
active after insert or update or delete position 0
AS
declare variable ida integer;
begin
update A
set maxdate=maxdate
where ida=:ida;
if (deleting) then
ida = old.ida;
else
ida = new.ida;
update A
set maxdate=(select max(dateb) from B where B.ida= :ida)
where ida=:ida;
end
-
- Заслуженный разработчик
- Сообщения: 1436
- Зарегистрирован: 15 сен 2005, 09:05
Re: Возможно ли это корректно сделать?
Теоретически-то, конечно, можно, но зачем? Не хватает производительности у запроса? Создай descending индекс на ida, dateb.Eugeneus2010 писал(а):Возможно ли на тригерах так организовать обновление поля maxdate, чтобы оно всегда было равно (select max(dateb) from B where B.ida=A.ida) ?
Re: Возможно ли это корректно сделать?
Вообще триггер паршивый. Зачем постоянно считать max, если в A уже есть максимальная дата, а в триггере известно, что вставляется или обновляется в текущей записи b? С другой стороны, Вы пытаетесь сначала заблокировать запись в A, а я Вам об этом и сказал, что она ОДНА, а пользователей, которые вставляют запись в B с одинаковым ida может быть несколько. Так что все кроме первого получат конфликт обновления, который Вам нужно будет обрабатывать. То есть узкое горло будет на апдейте вот этой самой одной записи where ida=:ida.kdv, вопрос как раз в том, как обеспечить целостность данных.
триггер работает в контексте вызвавшей его транзации. То есть, триггер никогда не видит чужих не-committed-изменений. Но Вы блокируете запись в начале триггера. Так что по идее - обеспечит. Но - см. выше.Обеспечит ли такой триггер целостность при условии, что все обновления будут запускаться в транзакциях с параметрами read_committed nowait ?
-
- Сообщения: 4
- Зарегистрирован: 11 сен 2010, 17:31
Re: Возможно ли это корректно сделать?
kdv, спасибо, про блокировку понятно. В моем случае она к большим проблемам привести не должна, в отличие от некорректного значения maxdate. Разве можно обойтись без нее?
Я вставил первый блокирующий UPDATE для того, чтобы не получилась ситуация, когда другая транзакция меняет maxdate и успевает закоммитится после получения первой транзакцией значения select, но перед выполнением первой транзакцией UPDATE A - в таком случае в maxdate может оказаться неверное значение.
В какой момент блокируется запись в таблице A при
update A set maxdate=(select max(dateb) from B where B.ida= :ida) where ida=:ida;
-- до вычисления select или после него?
Да, при вставке без select можно обойтись, при обновлении и удалении уже не всегда. Согласен, что тригера можно оптимизировать в этом смысле.Зачем постоянно считать max, если в A уже есть максимальная дата, а в триггере известно, что вставляется или обновляется в текущей записи b
Я вставил первый блокирующий UPDATE для того, чтобы не получилась ситуация, когда другая транзакция меняет maxdate и успевает закоммитится после получения первой транзакцией значения select, но перед выполнением первой транзакцией UPDATE A - в таком случае в maxdate может оказаться неверное значение.
В какой момент блокируется запись в таблице A при
update A set maxdate=(select max(dateb) from B where B.ida= :ida) where ida=:ida;
-- до вычисления select или после него?
-
- Сообщения: 4
- Зарегистрирован: 11 сен 2010, 17:31
Re: Возможно ли это корректно сделать?
Есть доводы за и против. Интересует принципиальная возможность этого варианта.Теоретически-то, конечно, можно, но зачем? Не хватает производительности у запроса? Создай descending индекс на ida, dateb.