![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
KEY VIOLATION при выполнении процедуры. [D6, IB6.x]
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