Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

KEY VIOLATION при выполнении процедуры. [D6, IB6.x]


Страницы:   1 2 3

Vuk ©   (2004-01-21 14:38:00) 

Давно не ковырялся с Interbase, но тут пришлось...
Результаты странные. Получил KEY VIOLATION при выполнении поцедуры со следующей логикой:

CREATE PROCEDURE SomeProc(
KeyField1 INTEGER,
KeyField2 INTEGER,
value INTEGER)
AS
begin

if (exists(select 1 from SomeTable where (KeyField1 =:KeyField1) and (KeyField2 = :KeyField2))) then
update
SomeTable
set
Value = :Value
where
(KeyField1 = :KeyField1) and
(KeyField2 = :KeyField2);
else
insert into SomeTable (
KeyField1,
KeyField2,
Value
)
values(
:KeyField1,
:KeyField2,
:Value );
end


У кого-нибудь есть мысли, как такое может получиться?

Добавлю, что эта процедура вызывается из другой в рамках достаточно длительной по времени (работа с сервером через интернет) транзакции. PK в SomeTable составной (KeyField1, KeyField2).


Johnmen   (2004-01-21 17:18:00) [21]

>jack128 © (21.01.04 17:05)

Да. Это понятно...
Возможно, именно из-за "долгой" обработки ексепшенов...

>Vuk © (21.01.04 17:07)
>Спишем на полтергейст.

Разумно, однозначно...:))))))


jack128   (2004-01-21 17:08:00) [22]


> Johnmen © (21.01.04 17:05) [21]

Вообще, то многие пишут IB6.x имея в виду все клоны :-)
А в FB1.5 есть ROW_COUNT


Vuk   (2004-01-21 17:07:00) [23]

to Johnmen:
>Но это опять же, если более одной транзакции одновременно. А ты
>говоришь, что одна...
А даже если и не одна. В режиме read commited, если одна транзакция нарвется на данные, меняемые другой транзакцией, получим deadlock. То есть должна была пройти именно вставка, но такой транзакции быть не могло однозначно - шла отладка приложения и оно было только на одной машине. Могли ли повлиять предыдущие транзакции, результатом которых была вставка строк в эту же таблицу? Думаю вряд ли, все-таки режим read commited. Может, конечно, как-то помешал открытый IBExpert... Но опять же транзакций на обновление/вставку оттуда не было...

>Большие тормоза как раз в приведенном автором примере -
>выполнение "лишнего" запроса (SELECT...).
Это по PK тормоза? Нафига тогда такой сервер, если выборки по PK в нем тормозят?

to Sandman25:
>Надеюсь, в IB есть аналог RowsAffected.
Вот именно этого-то там как раз и нет.

to jack128:
>А вчем причина ошибки, все таки не понятно..
Во-во. :o) Было б понятно - не писал бы.

В общем - фиг с ним. Пока больше проблема не повторялась. Может больше и не повторится. Спишем на полтергейст. :o)


jack128   (2004-01-21 17:05:00) [24]


> Кстати, примеры, приведенные в статье, не совсем "состыковываются"
> с приведенным Vuk. Причем принципиально-существенно.
Это почему? Я разницу увидел, тоолько в том, что в статье в процедуре вставляется сразу много записей, а в у Vuk"a - одна. Ну так я и сказал, что "при больших объемах"


> UPDATE table my_table SET my_value = pMyValue WHERE id =
> pMyId;
/*В этот момент другой клиент вставляет запись с нашим PK*/
> IF DBINFO("SQLCA.SQLERRD1") = 0 THEN
> INSERT INTO my_table ... /*здесь ошибка*/
> END IF;


Johnmen   (2004-01-21 17:05:00) [25]

>Sandman25 © (21.01.04 16:54)

Мы же IB ковыряем. Хранимую процедуру. Узнать, сколько проапдейтилось, это проблема в рамках ХП...


Sandman25   (2004-01-21 16:54:00) [26]

[13] Johnmen © (21.01.04 16:20)
[14] jack128 © (21.01.04 16:25)

Да нет, именно сначала update, а потом insert. И никакого замедления, потому что не будет ни Exception, ни затрат на подсчет RowsAffected.
Дело в том, что Informix для любой команды SQL всегдасчитает количество затронутых записей и получение этого числа - всего лишь вызов специальной функции, выполняющей чтение из специальной структуры, находящейся в RAM. Кстати, в эту же структуру INSERT заносит вставленное значение автоинкрементного поля.

Имеем нечто такое:

UPDATE table my_table SET my_value = pMyValue WHERE id = pMyId;
IF DBINFO("SQLCA.SQLERRD1") = 0 THEN
INSERT INTO my_table ...
END IF;


Johnmen   (2004-01-21 16:52:00) [27]

>jack128 © (21.01.04 16:45)

Учитываю.
Кстати, примеры, приведенные в статье, не совсем "состыковываются" с приведенным Vuk. Причем принципиально-существенно. Посему подымаю свою реплику [15]
:)


Johnmen   (2004-01-21 16:45:00) [28]

>jack128 © (21.01.04 16:39) [16]

А ведь когда-то я читал это...:)
Наверное, авторы статьи правы. И тоже прав. А я нет...


jack128   (2004-01-21 16:45:00) [29]


> > Johnmen © (21.01.04 16:35) [15]
Ты почему то не учитываешь, что операция записи значительно "тяжелее", чем операция чтения. А уж если, чтение индексированное...


jack128   (2004-01-21 16:39:00) [30]


> Johnmen © (21.01.04 16:35) [15]

http://www.ibase.ru/devinfo/testiu.htm


Johnmen   (2004-01-21 16:35:00) [31]

>jack128 © (21.01.04 16:25)

Б ольшие тормоза как раз в приведенном автором примере - выполнение "лишнего" запроса (SELECT...).


jack128   (2004-01-21 16:25:00) [32]


> Sandman25 © (21.01.04 16:13) [12]
> Johnmen © (21.01.04 16:20) [13]
На больших объмах тормоза будут, ого-го. Лудше комбинированный вариант.
if exists() then
insert ..
else
begin
update ...
when <не знаю, что тут писать :-) > do
begin
insert...
end
end
Хотя наверно, бредово выглядит..

А вчем причина ошибки, все таки не понятно..


Johnmen   (2004-01-21 16:20:00) [33]

>Sandman25 © (21.01.04 16:13)

Только наоборот :) Сначала insert, и если ошибка, то update.


Sandman25   (2004-01-21 16:13:00) [34]

Vuk

Хранимая с предпроверкой перед вставкой уязвима для подобных ошибок. Лучше пытайтесь сразу сделать update, и если он не прошел (RowsAffected=0), то значит, придется делать insert. Надеюсь, в IB есть аналог RowsAffected.

PS. По крайней мере в одной другой СУБД он есть.


Johnmen   (2004-01-21 16:07:00) [35]

>Vuk © (21.01.04 15:54)

Если нет, то странно...

>Но ведь вставка в процедуре происходит только в случае, если
>запись в таблице отсутствует

В описанном случае это не совсем так, я думаю. Потому, что между проверкой существования (SELECT..) и модифицирующими действиями (UPDATE..., INSERT...) проходит какое-то время, в течении которого другой запрос другой транзакции тоже что-то сделает...:)
Но это опять же, если более одной транзакции одновременно. А ты говоришь, что одна...


Vuk   (2004-01-21 15:54:00) [36]

to Johnmen:
Конкурирующих транзакций на обновление по идее не должно было быть. А выборки на обновления влиять не должны. К тому же ошибка то - key violation. Т.е. попытка вставить запись, которая нарушает PK. Но ведь вставка в процедуре происходит только в случае, если запись в таблице отсутствует. Или в IB такое сообщение об ошибке имеет другой смысл?

to Vlad:
>Вероятнее всего - тебе нужен уровень изоляции SNAPSHOT TABLE
>STABILITY
Вот это вполне может подойти по смыслу производимых изменений в БД. Сейчас стоит read commited.


Sandman25   (2004-01-21 15:29:00) [37]

[8] jack128 © (21.01.04 15:26)

установить время

SET LOCK MODE TO WAIT 10
Но это не для IB, конечно.


jack128   (2004-01-21 15:26:00) [38]


> Судя по описанию, можно попробовать установить время ожидания,
> чтобы не было "no wait transaction"
Тогда возможны deadlock"и.
Если у Vuk"a в программе действительно возникают конкурирующие тр-ции, то это весьма вероятно..


Sandman25   (2004-01-21 15:24:00) [39]

[4] Vuk © (21.01.04 15:05)

Судя по описанию, можно попробовать установить время ожидания, чтобы не было " no waittransaction"


Vlad   (2004-01-21 15:22:00) [40]


> Vuk © (21.01.04 15:05) [4]

Вероятнее всего - тебе нужен уровень изоляции SNAPSHOT TABLE STABILITY
почитай тут:
http://www.ibase.ru/devinfo/ibxtrans.htm


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо