Страница 1 из 1

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

Добавлено: 11 сен 2010, 17:34
Eugeneus2010
Есть две таблицы

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: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 00:07
kdv
триггеры работатют только в контексте пользовательских транзакций, так что при определенных условиях на целостность данных, обновляемых таким образом, расчитывать не стоит.
Кроме того, как я понимаю, связь b к a это "много к одной", а значит если несколько пользователей обновят B, то они могут столкнуться по конфликту обновления (триггером) одной и той же записи в A.

Насчет, "возможно ли это корректно сделать" - неясен вопрос. Написать такой триггер можно без проблем. Вы пробовали?

Re: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 01:07
Eugeneus2010
kdv, вопрос как раз в том, как обеспечить целостность данных.

Код: Выделить всё

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
Обеспечит ли такой триггер целостность при условии, что все обновления будут запускаться в транзакциях с параметрами read_committed nowait ?

Re: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 13:44
Dimitry Sibiryakov
Eugeneus2010 писал(а):Возможно ли на тригерах так организовать обновление поля maxdate, чтобы оно всегда было равно (select max(dateb) from B where B.ida=A.ida) ?
Теоретически-то, конечно, можно, но зачем? Не хватает производительности у запроса? Создай descending индекс на ida, dateb.

Re: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 14:13
kdv
kdv, вопрос как раз в том, как обеспечить целостность данных.
Вообще триггер паршивый. Зачем постоянно считать max, если в A уже есть максимальная дата, а в триггере известно, что вставляется или обновляется в текущей записи b? С другой стороны, Вы пытаетесь сначала заблокировать запись в A, а я Вам об этом и сказал, что она ОДНА, а пользователей, которые вставляют запись в B с одинаковым ida может быть несколько. Так что все кроме первого получат конфликт обновления, который Вам нужно будет обрабатывать. То есть узкое горло будет на апдейте вот этой самой одной записи where ida=:ida.
Обеспечит ли такой триггер целостность при условии, что все обновления будут запускаться в транзакциях с параметрами read_committed nowait ?
триггер работает в контексте вызвавшей его транзации. То есть, триггер никогда не видит чужих не-committed-изменений. Но Вы блокируете запись в начале триггера. Так что по идее - обеспечит. Но - см. выше.

Re: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 17:45
Eugeneus2010
kdv, спасибо, про блокировку понятно. В моем случае она к большим проблемам привести не должна, в отличие от некорректного значения maxdate. Разве можно обойтись без нее?
Зачем постоянно считать max, если в A уже есть максимальная дата, а в триггере известно, что вставляется или обновляется в текущей записи b
Да, при вставке без select можно обойтись, при обновлении и удалении уже не всегда. Согласен, что тригера можно оптимизировать в этом смысле.

Я вставил первый блокирующий UPDATE для того, чтобы не получилась ситуация, когда другая транзакция меняет maxdate и успевает закоммитится после получения первой транзакцией значения select, но перед выполнением первой транзакцией UPDATE A - в таком случае в maxdate может оказаться неверное значение.

В какой момент блокируется запись в таблице A при
update A set maxdate=(select max(dateb) from B where B.ida= :ida) where ida=:ida;
-- до вычисления select или после него?

Re: Возможно ли это корректно сделать?

Добавлено: 12 сен 2010, 18:25
Eugeneus2010
Теоретически-то, конечно, можно, но зачем? Не хватает производительности у запроса? Создай descending индекс на ida, dateb.
Есть доводы за и против. Интересует принципиальная возможность этого варианта.