Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.08.08;
Скачать: CL | DM;

Вниз

INSERT/UPDATE в одном флаконе   Найти похожие ветки 

 
Piter ©   (2004-07-11 18:41) [0]

Есть база с записями. У каждой записи есть уникальное числовое поле, допустим UnicField.

Есть функция, которая добавляет записи в базу, в эту функцию передаются нужные значения полей записей. И функция анализирует, есть ли уже запись с таким значенем поля UnicField в базе или нету. Если есть - она обновляет остальные поля нужной записи (UPDATE), если нету - то добавляет новую запист (INSERT).

Сейчас организовано так - функция делает выборку SELECT COUNT с нужным значением UnicField, и если получится ноль - то добавляет запись, иначе - обновляет существующую. Но дело в том, что все это работает очень медленно. Добавление/обновление 500 записей длится около 7 секунд (Athlon 1800+), При этом чистое добавление записей (без выяснения есть ли запись с таким уникальным UnicField) длится меньше секунды.

Можно как-то сделать такую команду, чтобы запись если существует обновлялась, если не существует - то добавлялась новая запись?

P.S. База - Firebird


 
Vlad ©   (2004-07-11 18:54) [1]


> Добавление/обновление 500 записей длится около 7 секунд
> (Athlon 1800+), При этом чистое добавление записей (без
> выяснения есть ли запись с таким уникальным UnicField) длится
> меньше секунды.


Похоже что у тебя запрос на выборку записей неоптимизированный.

Если выборка производится по одному полю, как например:
SELECT Count(*) from table where MyUniqueField = SomeValue
то обязательно д.б. индекс по полю MyUniqueField

Если же выборка идет по нескольким полям, напр.
SELECT Count(*) from table where MyField1 = SomeValue1 and MyField2 = SomeValue2
В этом случае желательно создать составной индекс MyField1+MyField2


 
Piter ©   (2004-07-11 19:02) [2]

Vlad (11.07.04 18:54) [1]

спасибо... создал двойной индекс - теперь добавление длится пару секунд... а можно еще быстрее? Чтобы обойтись БЕЗ SELECT?


 
jack128 ©   (2004-07-11 19:09) [3]

помимо индексов нужно сделать хп в которой и проверять существует ли такая запись

if (exists(select 1 from table where UnicField = :UnicField)) then
begin
 update table
 set Fie1d1 = :Field1
     Field2 = :Field2
   ..
 where
   UnicField = :UnicField
end
else
begin
 insert into ....
end;


 
SergP ©   (2004-07-11 19:26) [4]


> Можно как-то сделать такую команду, чтобы запись если существует
> обновлялась, если не существует - то добавлялась новая запись?


У меня была подобная проблема. Пока я решил ее применением (юзаю ADO) ADOTable вместо ADOQuery, типа так:

       
   with AdoTable do
     begin
     if seek(Id,soFirstEQ) then edit else insert;
     FieldByName("MyField").AsInteger := ....;
     ...
     Post;
     end;

Не знаю насколько это хорошо, так как не рекомендуется юзать ADOTable, но правда база у меня локальная, и вроде особых тормозов с этим нет..

Есть еще такой вариант (правда я тоже не уверен в его скорости):
Создаем временную таблицу, куда запихиваем все данные, а затем двумя запросами переносим в основную таблицу сначала те записи с такими значениями уникального поля которые есть в основной таблице (Update)
а затем те, которых нет (INSERT)


 
Piter ©   (2004-07-11 20:53) [5]

jack128 (11.07.04 19:09) [3]
помимо индексов нужно сделать хп


что такое хп?


 
jack128 ©   (2004-07-11 21:17) [6]

хранимая процедура. Stored procedure.


 
Vlad ©   (2004-07-11 23:17) [7]

Впринципе можно и еще быстрее. Достаточно создать уникальный индекс, тогда попытка записи дубля будет приводить к исключению, которое можно соотв. образом обработать на клиенте.
Что-то вроде такого:
try
 IBSQLInsert.ExecQuery; // Попытка Insert
except
 on E: Exception do
 begin
   // анализ ошибки, если нарушение уникальности, тогда...
      IBSQLUpdate.ExecQuery; // Попытка Update
    else
      raise;
end;

Думаю, что это будет работать быстрее.


 
jack128 ©   (2004-07-11 23:28) [8]


> [7] Vlad ©   (11.07.04 23:17)
нет. Это будет работать медленнее. Значительно медленее. Все проверки нужно делать на сервере в хп. В общем как всегда www.ibase.ru ;-) А конкретно http://www.ibase.ru/devinfo/testiu.htm


 
Piter ©   (2004-07-12 00:50) [9]

jack128 (11.07.04 23:28) [8]

Дело в том, что база Firebird Embedded - то есть, она локальная. Имеет тогда смысл хп делать?


 
jack128 ©   (2004-07-12 01:01) [10]


> Имеет тогда смысл хп делать?
без понятия, не тестил. В любом случае [3] быстрее, чем [0] или [7],вопрос на сколько. Потесть - узнаешь, заодно нам расскажешь ;-)
Но делать "правильно" всегда лудше, чем делать "можно и лудше, но и так сойдет"  :-)


 
Piter ©   (2004-07-12 17:33) [11]

jack128 (12.07.04 01:01) [10]

Блин, все равно ты DMClient используешь...
:)


 
stone ©   (2004-07-12 17:55) [12]


> а можно еще быстрее? Чтобы обойтись БЕЗ SELECT?

Использовать две команды в одной транзакции
DELETE FROM ... WHERE UnicField = SomeValue
INSERT INTO ... VALUES ()

PS. Естественно, тут возможны нюансы, но общее направление такое...



Страницы: 1 вся ветка

Текущий архив: 2004.08.08;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.021 c
14-1090176989
GanibalLector
2004-07-18 22:56
2004.08.08
и это уже не в первый раз


14-1090606537
Ricks
2004-07-23 22:15
2004.08.08
www.hotbox.ru - что с ним


14-1089100382
Глеб
2004-07-06 11:53
2004.08.08
Изготовление справочной системы


14-1090180409
Palladin
2004-07-18 23:53
2004.08.08
Опрос про сон.


8-1085404170
Vadim
2004-05-24 17:09
2004.08.08
Иконки и кнопки