Blob and update

Запросы, планы, оптимизация запросов, ...

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

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Blob and update

Сообщение CCB » 20 июн 2006, 14:14

При апдейте поля типа BLOB происходит замедление этого самого апдейта. Изменяются примерно 100-300 записей по одной, на первых 20-30-ти работает нормально, а потом постепенно начинаются тормоза и после 50-70 записей тормоза просто жуткие. В чем может быть проблема?
Размер одной записи около килобайта с блобом.
FireBird 1.5, Delphi 6, IBX.

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

Сообщение kdv » 20 июн 2006, 15:27

скорее всего в использовании датасета для вставки блобов. используй IBSQL или IBQuery с оператором insert.

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 20 июн 2006, 15:37

kdv писал(а):скорее всего в использовании датасета для вставки блобов. используй IBSQL или IBQuery с оператором insert.
использую IBQuery (пробовал и IBSQL). зачем инсерт? тогда нужно предварительно убивать запись? при вставке наверняка индексы будут перестраивацца...

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

Сообщение kdv » 20 июн 2006, 16:24

зачем инсерт?
если обновляешь - тогда update. Ты читал
www.ibase.ru/devinfo/impexp.htm ? У тебя случай "импорта" данных, раз ты пишешь что
Изменяются примерно 100-300 записей
соответственно при движении по датасету у тебя скорее всего происходит перечитывание всего запроса. Это самая естественная причина замедления при выполнении идентичных операций.

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 08:09

kdv писал(а):
зачем инсерт?
если обновляешь - тогда update. Ты читал
www.ibase.ru/devinfo/impexp.htm ? У тебя случай "импорта" данных, раз ты пишешь что
Изменяются примерно 100-300 записей
соответственно при движении по датасету у тебя скорее всего происходит перечитывание всего запроса. Это самая естественная причина замедления при выполнении идентичных операций.
сцылку почитал.
вот как у меня реализовано:
(пробовал и IBSQL вместо IBQuery)

while not IBQueryMain.Eof do
begin
IBQueryUPD.SQL.Clear;
IBQueryUPD.SQL.Add('update Objects set Info=:ParamInfo where ID='+IBQueryMain.FieldByName('IDObj').AsString);
Stream:=TStringStream.Create(StrStream);
Stream.WriteComponent(Info);
Stream.Seek(0, soFromBeginning);
IBQueryUPD.ParamByName('ParamInfo').LoadFromStream(Stream, ftBlob);
IBQueryUPD.ExecSQL;
Stream.Free;
IBQueryMain.Next
end;


в поле Info типа Blob сохраняются свойства объектов, иногда (крайне редко) эти свойства нужно изменить сразу у 100-300 объектов и тут начинаецца описаное выше...
честно признаюсь - при чем тут импорт/экспорт не понимаю...

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 10:17

AlexandrS писал(а):Глупый конечно вопрос, но все же. Индекс на поле IDObj стоит? Если нет, то поставьте.
primary key

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 21 июн 2006, 11:51

AlexandrS писал(а):Думаю вот так по быстрее должно быть, хотя не проверял:
Создание/удаление объекта TStream настолько быстрая процедура, что на работу не повлияет.

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 11:59

WildSery писал(а):
AlexandrS писал(а):Думаю вот так по быстрее должно быть, хотя не проверял:
Создание/удаление объекта TStream настолько быстрая процедура, что на работу не повлияет.
я канешна сильно звиняюсь, но вопрос не про стрим, а то мы щас уползем совсем в другую сторону... кстати? этот код из старой версии, реально используецца не TStringStream, а TMemoryStream...

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 21 июн 2006, 12:09

CCB писал(а):я канешна сильно звиняюсь, но вопрос не про стрим, а то мы щас уползем совсем в другую сторону... кстати? этот код из старой версии, реально используецца не TStringStream, а TMemoryStream...
Никто никуда не уползает. Был дан совет переделать без создания TStream, что мол будет быстрее. Я ответил, что быстрее не будет, совет практически бесполезен. Какой именно поток используется, блобу до лампочки, это всё потомки от TStream.

Если коммит каждого изменения делать? Или это недопустимо логикой алгоритма?

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 12:34

WildSery писал(а):Если коммит каждого изменения делать? Или это недопустимо логикой алгоритма?
щас именно так и делается, но пробовал разные варианты - т.к. обекты принадлежат разным классам, то, по логике программы, изменение скажем объекта верхнего уровня влечет за собой изменение нескольких, принадлежащих ему, объектов, так вот пробовал делать коммит после изменения объектов верхнего уровня, потом после измения объекта нижнего уровня, уровней этих, если быть более конкретным, три... так же пробовал делать коммит после всех изменений...

Merlin
Динозавр IB/FB
Сообщения: 1502
Зарегистрирован: 27 окт 2004, 11:44

Сообщение Merlin » 21 июн 2006, 13:26

CCB писал(а): сцылку почитал.
Хреново почитал.
CCB писал(а): not IBQueryMain.Eof do
begin
IBQueryUPD.SQL.Clear;
IBQueryUPD.SQL.Add('update Objects set Info=:ParamInfo where ID='+IBQueryMain.FieldByName('IDObj').AsString);
Stream:=TStringStream.Create(StrStream);
Stream.WriteComponent(Info);
Stream.Seek(0, soFromBeginning);
IBQueryUPD.ParamByName('ParamInfo').LoadFromStream(Stream, ftBlob);
IBQueryUPD.ExecSQL;
Stream.Free;
IBQueryMain.Next
end;
Во-первых, смысл? (C) Штирлиц. Собирать один и тот же запрос с параметром в цикле и как результат на каждом шагу его препарить. Вместо того, чтоб собрать один раз перед циклом с двумя параметрами и в цикле только вызывать? Но это так, лирика. Основная твоя проблема - на клиенте кончается память, которую сжирает IBQueryMain, буферизуя всё прочитанное. Поставь ей UniDirectional=True и будет тебе щастье. И это ведь всё разжевано там где ты "почитал".

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 14:04

Merlin писал(а):Во-первых, смысл? (C) Штирлиц. Собирать один и тот же запрос с параметром в цикле и как результат на каждом шагу его препарить. Вместо того, чтоб собрать один раз перед циклом с двумя параметрами и в цикле только вызывать? Но это так, лирика.
с этим смогласен...
Основная твоя проблема - на клиенте кончается память, которую сжирает IBQueryMain, буферизуя всё прочитанное. Поставь ей UniDirectional=True и будет тебе щастье. И это ведь всё разжевано там где ты "почитал".
а ты это щастье пробовал? попробуй... нихрена это не помогает... скорость падает примерно с тем же ускорением...

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 21 июн 2006, 15:46

завтра расскажу, как я пытался исправить ситуацию...

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 22 июн 2006, 07:54

кароче:
я убрал цикл while - нужные данные загружаю в динамический массив и хожу по массиву; TIBQuery заменил на TIBSQL, запрос строю именно так, как написал Merlin; пробовал TIBSQL создавать динамически в каждой итерации... ничего не помогает - скорость работы постепенно падает... так что пока остаецца грешить на сервер, чего-то он там делает мне неизвестное...

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 22 июн 2006, 08:39

Какой размер базы? И дай-ка статистику по ней =)

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 22 июн 2006, 08:53

размер около 900 мб

только што сделал бэкап\рестори

Database header page information:
Flags 0
Checksum 12345
Generation 1036
Page size 4096
ODS version 10.1
Oldest transaction 1026
Oldest active 1027
Oldest snapshot 1027
Next transaction 1030
Bumped transaction 1
Sequence number 0
Next attachment ID 0
Implementation ID 16
Shadow count 0
Page buffers 0
Next header page 0
Database dialect 3
Creation date Jun 22, 2006 8:35:22
Attributes force write

Variable header data:
Sweep interval: 20000
*END*

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 22 июн 2006, 09:06

Настораживает Page buffers 0, Attributes force write и Page size 4096.
1. Как-нибудь попробуй сделать page size = 8192. Должно повлиять на производительность.
2. Сними Force Writes.
3. Поставь Page Buffers = 1024.
Скажи результат.
Какая ось и размер оперативки на компе?

CCB
Сообщения: 35
Зарегистрирован: 20 июн 2006, 14:06

Сообщение CCB » 22 июн 2006, 09:12

1. Вот только што была 16384, при последнем рестори сделал 4096
2. Только вчера вечером установил в ON
3. Это попробую

WinXP SP2, 512

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 22 июн 2006, 09:22

Кстати, не проверял, в каком месте программы тормозит? Точно после ExecSQL? Создай экземпляр TStringList, закидывай в него текущее время в разных точках кода (например, в начале цикла, перед и после ExecSQL), а потом сохрани все в файл. Изучи цифры.

Ответить