Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2004.08.08;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.48 MB
Время: 0.03 c
6-1086278285
Micah'GF
2004-06-03 19:58
2004.08.08
WinSock: глючит recvfrom


3-1089618268
LizaX
2004-07-12 11:44
2004.08.08
Проблема исспользования строковых ф-ций в SQL-запросе


14-1090187812
Piter
2004-07-19 01:56
2004.08.08
Вкладка Diagram в Code Explorer


4-1088592610
nik7777
2004-06-30 14:50
2004.08.08
Как перехватить изменения в реестре


4-1088015966
FragMan
2004-06-23 22:39
2004.08.08
Как послать Сtrl+V приложению?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский