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

Модераторы: kdv, CyberMax

Ответить
Eugeneus2010
Сообщения: 4
Зарегистрирован: 11 сен 2010, 17:31

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

Сообщение Eugeneus2010 » 11 сен 2010, 17:34

Есть две таблицы

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.

kdv
Forum Admin
Сообщения: 6575
Зарегистрирован: 25 окт 2004, 18:07
Контактная информация:

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

Сообщение kdv » 12 сен 2010, 00:07

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

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

Eugeneus2010
Сообщения: 4
Зарегистрирован: 11 сен 2010, 17:31

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

Сообщение Eugeneus2010 » 12 сен 2010, 01:07

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 ?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1427
Зарегистрирован: 15 сен 2005, 09:05
Откуда: Krupka
Контактная информация:

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

Сообщение Dimitry Sibiryakov » 12 сен 2010, 13:44

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

kdv
Forum Admin
Сообщения: 6575
Зарегистрирован: 25 окт 2004, 18:07
Контактная информация:

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

Сообщение kdv » 12 сен 2010, 14:13

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

Eugeneus2010
Сообщения: 4
Зарегистрирован: 11 сен 2010, 17:31

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

Сообщение Eugeneus2010 » 12 сен 2010, 17:45

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 или после него?

Eugeneus2010
Сообщения: 4
Зарегистрирован: 11 сен 2010, 17:31

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

Сообщение Eugeneus2010 » 12 сен 2010, 18:25

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

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость